Back to index

lightning-sunbird  0.9+nobinonly
nsStandardURL.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@netscape.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifndef nsStandardURL_h__
00040 #define nsStandardURL_h__
00041 
00042 #include "nsString.h"
00043 #include "nsDependentString.h"
00044 #include "nsDependentSubstring.h"
00045 #include "nsISerializable.h"
00046 #include "nsIFileURL.h"
00047 #include "nsIStandardURL.h"
00048 #include "nsIFile.h"
00049 #include "nsIURLParser.h"
00050 #include "nsIUnicodeEncoder.h"
00051 #include "nsIObserver.h"
00052 #include "nsIIOService.h"
00053 #include "nsCOMPtr.h"
00054 #include "nsURLHelper.h"
00055 
00056 class nsIBinaryInputStream;
00057 class nsIBinaryOutputStream;
00058 class nsIIDNService;
00059 class nsICharsetConverterManager;
00060 class nsIPrefBranch;
00061 
00062 //-----------------------------------------------------------------------------
00063 // standard URL implementation
00064 //-----------------------------------------------------------------------------
00065 
00066 class nsStandardURL : public nsIFileURL
00067                     , public nsIStandardURL
00068                     , public nsISerializable
00069                     , public nsIClassInfo
00070 {
00071 public:
00072     NS_DECL_ISUPPORTS
00073     NS_DECL_NSIURI
00074     NS_DECL_NSIURL
00075     NS_DECL_NSIFILEURL
00076     NS_DECL_NSISTANDARDURL
00077     NS_DECL_NSISERIALIZABLE
00078     NS_DECL_NSICLASSINFO
00079 
00080     nsStandardURL(PRBool aSupportsFileURL = PR_FALSE);
00081     virtual ~nsStandardURL();
00082 
00083     static void InitGlobalObjects();
00084     static void ShutdownGlobalObjects();
00085 
00086 public: /* internal -- HPUX compiler can't handle this being private */
00087     //
00088     // location and length of an url segment relative to mSpec
00089     //
00090     struct URLSegment
00091     {
00092         PRUint32 mPos;
00093         PRInt32  mLen;
00094 
00095         URLSegment() : mPos(0), mLen(-1) {}
00096         URLSegment(PRUint32 pos, PRInt32 len) : mPos(pos), mLen(len) {}
00097         void Reset() { mPos = 0; mLen = -1; }
00098     };
00099 
00100     //
00101     // Pref observer
00102     //
00103     class nsPrefObserver : public nsIObserver
00104     {
00105     public:
00106         NS_DECL_ISUPPORTS
00107         NS_DECL_NSIOBSERVER
00108 
00109         nsPrefObserver() { }
00110     };
00111     friend class nsPrefObserver;
00112 
00113     //
00114     // URL segment encoder : performs charset conversion and URL escaping.
00115     //
00116     class nsSegmentEncoder
00117     {
00118     public:
00119         nsSegmentEncoder(const char *charset);
00120 
00121         // Encode the given segment if necessary, and return the length of
00122         // the encoded segment.  The encoded segment is appended to |buf|
00123         // if and only if encoding is required.
00124         PRInt32 EncodeSegmentCount(const char *str,
00125                                    const URLSegment &segment,
00126                                    PRInt16 mask,
00127                                    nsAFlatCString &buf,
00128                                    PRBool& appended);
00129          
00130         // Encode the given string if necessary, and return a reference to
00131         // the encoded string.  Returns a reference to |buf| if encoding
00132         // is required.  Otherwise, a reference to |str| is returned.
00133         const nsACString &EncodeSegment(const nsASingleFragmentCString &str,
00134                                         PRInt16 mask,
00135                                         nsAFlatCString &buf);
00136     private:
00137         PRBool InitUnicodeEncoder();
00138         
00139         const char* mCharset;  // Caller should keep this alive for
00140                                // the life of the segment encoder
00141         nsCOMPtr<nsIUnicodeEncoder> mEncoder;
00142     };
00143     friend class nsSegmentEncoder;
00144 
00145 protected:
00146     virtual nsStandardURL* StartClone();
00147 
00148     // Helper for subclass implementation of GetFile().  Subclasses that map
00149     // URIs to files in a special way should implement this method.  It should
00150     // ensure that our mFile is initialized, if it's possible.
00151     virtual nsresult EnsureFile();
00152 
00153 private:
00154     PRInt32  Port() { return mPort == -1 ? mDefaultPort : mPort; }
00155 
00156     void     Clear();
00157     void     InvalidateCache(PRBool invalidateCachedFile = PR_TRUE);
00158 
00159     PRBool   EscapeIPv6(const char *host, nsCString &result);
00160     PRBool   NormalizeIDN(const nsCSubstring &host, nsCString &result);
00161     void     CoalescePath(netCoalesceFlags coalesceFlag, char *path);
00162 
00163     PRUint32 AppendSegmentToBuf(char *, PRUint32, const char *, URLSegment &, const nsCString *esc=nsnull, PRBool useEsc = PR_FALSE);
00164     PRUint32 AppendToBuf(char *, PRUint32, const char *, PRUint32);
00165 
00166     nsresult BuildNormalizedSpec(const char *spec);
00167 
00168     PRBool   SegmentIs(const URLSegment &s1, const char *val);
00169     PRBool   SegmentIs(const char* spec, const URLSegment &s1, const char *val);
00170     PRBool   SegmentIs(const URLSegment &s1, const char *val, const URLSegment &s2);
00171 
00172     PRInt32  ReplaceSegment(PRUint32 pos, PRUint32 len, const char *val, PRUint32 valLen);
00173     PRInt32  ReplaceSegment(PRUint32 pos, PRUint32 len, const nsACString &val);
00174 
00175     nsresult ParseURL(const char *spec, PRInt32 specLen);
00176     nsresult ParsePath(const char *spec, PRUint32 pathPos, PRInt32 pathLen = -1);
00177 
00178     char    *AppendToSubstring(PRUint32 pos, PRInt32 len, const char *tail, PRInt32 tailLen = -1);
00179 
00180     // dependent substring helpers
00181     const nsDependentCSubstring Segment(PRUint32 pos, PRInt32 len); // see below
00182     const nsDependentCSubstring Segment(const URLSegment &s) { return Segment(s.mPos, s.mLen); }
00183 
00184     // dependent substring getters
00185     const nsDependentCSubstring Prepath();  // see below
00186     const nsDependentCSubstring Scheme()    { return Segment(mScheme); }
00187     const nsDependentCSubstring Userpass(PRBool includeDelim = PR_FALSE); // see below
00188     const nsDependentCSubstring Username()  { return Segment(mUsername); }
00189     const nsDependentCSubstring Password()  { return Segment(mPassword); }
00190     const nsDependentCSubstring Hostport(); // see below
00191     const nsDependentCSubstring Host();     // see below
00192     const nsDependentCSubstring Path()      { return Segment(mPath); }
00193     const nsDependentCSubstring Filepath()  { return Segment(mFilepath); }
00194     const nsDependentCSubstring Directory() { return Segment(mDirectory); }
00195     const nsDependentCSubstring Filename(); // see below
00196     const nsDependentCSubstring Basename()  { return Segment(mBasename); }
00197     const nsDependentCSubstring Extension() { return Segment(mExtension); }
00198     const nsDependentCSubstring Param()     { return Segment(mParam); }
00199     const nsDependentCSubstring Query()     { return Segment(mQuery); }
00200     const nsDependentCSubstring Ref()       { return Segment(mRef); }
00201 
00202     // shift the URLSegments to the right by diff
00203     void ShiftFromAuthority(PRInt32 diff) { mAuthority.mPos += diff; ShiftFromUsername(diff); }
00204     void ShiftFromUsername(PRInt32 diff)  { mUsername.mPos += diff; ShiftFromPassword(diff); }
00205     void ShiftFromPassword(PRInt32 diff)  { mPassword.mPos += diff; ShiftFromHost(diff); }
00206     void ShiftFromHost(PRInt32 diff)      { mHost.mPos += diff; ShiftFromPath(diff); }
00207     void ShiftFromPath(PRInt32 diff)      { mPath.mPos += diff; ShiftFromFilepath(diff); }
00208     void ShiftFromFilepath(PRInt32 diff)  { mFilepath.mPos += diff; ShiftFromDirectory(diff); }
00209     void ShiftFromDirectory(PRInt32 diff) { mDirectory.mPos += diff; ShiftFromBasename(diff); }
00210     void ShiftFromBasename(PRInt32 diff)  { mBasename.mPos += diff; ShiftFromExtension(diff); }
00211     void ShiftFromExtension(PRInt32 diff) { mExtension.mPos += diff; ShiftFromParam(diff); }
00212     void ShiftFromParam(PRInt32 diff)     { mParam.mPos += diff; ShiftFromQuery(diff); }
00213     void ShiftFromQuery(PRInt32 diff)     { mQuery.mPos += diff; ShiftFromRef(diff); }
00214     void ShiftFromRef(PRInt32 diff)       { mRef.mPos += diff; }
00215 
00216     // fastload helper functions
00217     nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);
00218     nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &);
00219 
00220     static void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
00221 
00222     // IDN routines
00223     static nsresult ACEtoDisplayIDN(const nsCSubstring &in, nsCString &out);
00224     static nsresult UTF8toDisplayIDN(const nsCSubstring &in, nsCString &out);
00225     static PRBool IsInWhitelist(const nsCSubstring &host);
00226 
00227     // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
00228     nsCString mSpec;
00229     PRInt32   mDefaultPort;
00230     PRInt32   mPort;
00231 
00232     // url parts (relative to mSpec)
00233     URLSegment mScheme;
00234     URLSegment mAuthority;
00235     URLSegment mUsername;
00236     URLSegment mPassword;
00237     URLSegment mHost;
00238     URLSegment mPath;
00239     URLSegment mFilepath;
00240     URLSegment mDirectory;
00241     URLSegment mBasename;
00242     URLSegment mExtension;
00243     URLSegment mParam;
00244     URLSegment mQuery;
00245     URLSegment mRef;
00246 
00247     nsCString              mOriginCharset;
00248     nsCOMPtr<nsIURLParser> mParser;
00249 
00250     // mFile is protected so subclasses can access it directly
00251 protected:
00252     nsCOMPtr<nsIFile>      mFile;  // cached result for nsIFileURL::GetFile
00253     
00254 private:
00255     char                  *mHostA; // cached result for nsIURI::GetHostA
00256 
00257     enum {
00258         eEncoding_Unknown,
00259         eEncoding_ASCII,
00260         eEncoding_UTF8
00261     };
00262 
00263     PRUint32 mHostEncoding    : 2; // eEncoding_xxx
00264     PRUint32 mSpecEncoding    : 2; // eEncoding_xxx
00265     PRUint32 mURLType         : 2; // nsIStandardURL::URLTYPE_xxx
00266     PRUint32 mMutable         : 1; // nsIStandardURL::mutable
00267     PRUint32 mSupportsFileURL : 1; // QI to nsIFileURL?
00268 
00269     // global objects.  don't use COMPtr as its destructor will cause a
00270     // coredump if we leak it.
00271     static nsIIDNService               *gIDN;
00272     static nsICharsetConverterManager  *gCharsetMgr;
00273     static PRBool                       gInitialized;
00274     static PRBool                       gEscapeUTF8;
00275     static PRBool                       gAlwaysEncodeInUTF8;
00276     static PRBool                       gShowPunycode;
00277     static nsIPrefBranch               *gIDNWhitelistPrefBranch;
00278 };
00279 
00280 #define NS_THIS_STANDARDURL_IMPL_CID                 \
00281 { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */         \
00282     0xb8e3e97b,                                      \
00283     0x1ccd,                                          \
00284     0x4b45,                                          \
00285     {0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7} \
00286 }
00287 
00288 //-----------------------------------------------------------------------------
00289 // Dependent substring getters
00290 //-----------------------------------------------------------------------------
00291 
00292 inline const nsDependentCSubstring
00293 nsStandardURL::Segment(PRUint32 pos, PRInt32 len)
00294 {
00295     if (len < 0) {
00296         pos = 0;
00297         len = 0;
00298     }
00299     return Substring(mSpec, pos, PRUint32(len));
00300 }
00301 
00302 inline const nsDependentCSubstring
00303 nsStandardURL::Prepath()
00304 {
00305     PRUint32 len = 0;
00306     if (mAuthority.mLen >= 0)
00307         len = mAuthority.mPos + mAuthority.mLen;
00308     return Substring(mSpec, 0, len);
00309 }
00310 
00311 inline const nsDependentCSubstring
00312 nsStandardURL::Userpass(int includeDelim)
00313 {
00314     PRUint32 pos=0, len=0;
00315     // if there is no username, then there can be no password
00316     if (mUsername.mLen > 0) {
00317         pos = mUsername.mPos;
00318         len = mUsername.mLen;
00319         if (mPassword.mLen >= 0)
00320             len += (mPassword.mLen + 1);
00321         if (includeDelim)
00322             len++;
00323     }
00324     return Substring(mSpec, pos, len);
00325 }
00326 
00327 inline const nsDependentCSubstring
00328 nsStandardURL::Hostport()
00329 {
00330     PRUint32 pos=0, len=0;
00331     if (mAuthority.mLen > 0) {
00332         pos = mHost.mPos;
00333         len = mAuthority.mPos + mAuthority.mLen - pos;
00334     }
00335     return Substring(mSpec, pos, len);
00336 }
00337 
00338 inline const nsDependentCSubstring
00339 nsStandardURL::Host()
00340 {
00341     PRUint32 pos=0, len=0;
00342     if (mHost.mLen > 0) {
00343         pos = mHost.mPos;
00344         len = mHost.mLen;
00345         if (mSpec.CharAt(pos) == '[' && mSpec.CharAt(pos + len - 1) == ']') {
00346             pos++;
00347             len -= 2;
00348         }
00349     }
00350     return Substring(mSpec, pos, len);
00351 }
00352 
00353 inline const nsDependentCSubstring
00354 nsStandardURL::Filename()
00355 {
00356     PRUint32 pos=0, len=0;
00357     // if there is no basename, then there can be no extension
00358     if (mBasename.mLen > 0) {
00359         pos = mBasename.mPos;
00360         len = mBasename.mLen;
00361         if (mExtension.mLen >= 0)
00362             len += (mExtension.mLen + 1);
00363     }
00364     return Substring(mSpec, pos, len);
00365 }
00366 
00367 #endif // nsStandardURL_h__