1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * Copyright 2000, 2010 Oracle and/or its affiliates.
7  *
8  * OpenOffice.org - a multi-platform office productivity suite
9  *
10  * This file is part of OpenOffice.org.
11  *
12  * OpenOffice.org is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 3
14  * only, as published by the Free Software Foundation.
15  *
16  * OpenOffice.org is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License version 3 for more details
20  * (a copy is included in the LICENSE file that accompanied this code).
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * version 3 along with OpenOffice.org.  If not, see
24  * <http://www.openoffice.org/license.html>
25  * for a copy of the LGPLv3 License.
26  *
27  ************************************************************************/
28 
29 #include <sal/config.h>
30 
31 #include <rtl/uri.hxx>
32 #include <rtl/ustring.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <ne_alloc.h>
35 #include "NeonUri.hxx"
36 #include "DAVException.hxx"
37 
38 #include "../inc/urihelper.hxx"
39 
40 using namespace webdav_ucp;
41 
42 // FIXME: not sure whether initializing a ne_uri statically is supposed to work
43 // the string fields of ne_uri are char*, not const char*
44 
45 #ifdef __GNUC__
46 #pragma GCC diagnostic ignored "-Wwrite-strings"
47 #endif
48 
49 namespace {
50 
51 const ne_uri g_sUriDefaultsHTTP  = { const_cast<char *>("http"),
52                                      const_cast<char *>(""),
53                                      const_cast<char *>(""),
54                                      DEFAULT_HTTP_PORT,
55                                      const_cast<char *>(""),
56                                      nullptr,
57                                      nullptr };
58 const ne_uri g_sUriDefaultsHTTPS = { const_cast<char *>("https"),
59                                      const_cast<char *>(""),
60                                      const_cast<char *>(""),
61                                      DEFAULT_HTTPS_PORT,
62                                      const_cast<char *>(""),
63                                      nullptr,
64                                      nullptr };
65 const ne_uri g_sUriDefaultsFTP   = { const_cast<char *>("ftp"),
66                                      const_cast<char *>(""),
67                                      const_cast<char *>(""),
68                                      DEFAULT_FTP_PORT,
69                                      const_cast<char *>(""),
70                                      nullptr,
71                                      nullptr };
72 } // namespace
73 
NeonUri(const ne_uri * inUri)74 NeonUri::NeonUri( const ne_uri * inUri )
75 {
76     if ( inUri == nullptr )
77         throw DAVException( DAVException::DAV_INVALID_ARG );
78 
79     char * uri = ne_uri_unparse( inUri );
80 
81     if ( uri == nullptr )
82         throw DAVException( DAVException::DAV_INVALID_ARG );
83 
84     init( OString( uri ), inUri );
85     ne_free( uri );
86 
87     calculateURI();
88 }
89 
NeonUri(const OUString & inUri)90 NeonUri::NeonUri( const OUString & inUri )
91 {
92     if ( inUri.isEmpty() )
93         throw DAVException( DAVException::DAV_INVALID_ARG );
94 
95     // #i77023#
96     OUString aEscapedUri( ucb_impl::urihelper::encodeURI( inUri ) );
97 
98     OString theInputUri(
99         aEscapedUri.getStr(), aEscapedUri.getLength(), RTL_TEXTENCODING_UTF8 );
100 
101     ne_uri theUri;
102     if ( ne_uri_parse( theInputUri.getStr(), &theUri ) != 0 )
103     {
104         ne_uri_free( &theUri );
105         throw DAVException( DAVException::DAV_INVALID_ARG );
106     }
107 
108     init( theInputUri, &theUri );
109     ne_uri_free( &theUri );
110 
111     calculateURI();
112 }
113 
init(const OString & rUri,const ne_uri * pUri)114 void NeonUri::init( const OString & rUri, const ne_uri * pUri )
115 {
116     // Complete URI.
117     const ne_uri * pUriDefs
118         = rUri.matchIgnoreAsciiCase( "ftp:" ) ?
119               &g_sUriDefaultsFTP :
120           rUri.matchIgnoreAsciiCase( "https:" ) ?
121               &g_sUriDefaultsHTTPS :
122               &g_sUriDefaultsHTTP;
123 
124     mScheme   = OStringToOUString(
125                     pUri->scheme ? pUri->scheme : pUriDefs->scheme,
126                     RTL_TEXTENCODING_UTF8 );
127     mUserInfo = OStringToOUString(
128                     pUri->userinfo ? pUri->userinfo : pUriDefs->userinfo,
129                     RTL_TEXTENCODING_UTF8 );
130     mHostName = OStringToOUString(
131                     pUri->host ? pUri->host : pUriDefs->host,
132                     RTL_TEXTENCODING_UTF8 );
133     mPort     = pUri->port > 0 ? pUri->port : pUriDefs->port;
134     mPath     = OStringToOUString(
135                     pUri->path ? pUri->path : pUriDefs->path,
136                     RTL_TEXTENCODING_UTF8 );
137 
138     if ( pUri->query )
139     {
140         mPath += "?" + OStringToOUString( pUri->query,  RTL_TEXTENCODING_UTF8 );
141     }
142 
143     if ( pUri->fragment )
144     {
145         mPath += "#" + OStringToOUString( pUri->fragment,  RTL_TEXTENCODING_UTF8 );
146     }
147 }
148 
calculateURI()149 void NeonUri::calculateURI ()
150 {
151     OUStringBuffer aBuf( 256 );
152     aBuf.append( mScheme );
153     aBuf.append( "://" );
154     if ( !mUserInfo.isEmpty() )
155     {
156         //TODO! differentiate between empty and missing userinfo
157         aBuf.append( mUserInfo );
158         aBuf.append( "@" );
159     }
160     // Is host a numeric IPv6 address?
161     if ( ( mHostName.indexOf( ':' ) != -1 ) &&
162          ( mHostName[ 0 ] != '[' ) )
163     {
164         aBuf.append( "[" );
165         aBuf.append( mHostName );
166         aBuf.append( "]" );
167     }
168     else
169     {
170         aBuf.append( mHostName );
171     }
172 
173     // append port, but only, if not default port.
174     bool bAppendPort = true;
175     switch ( mPort )
176     {
177     case DEFAULT_HTTP_PORT:
178         bAppendPort = mScheme != "http";
179         break;
180 
181     case DEFAULT_HTTPS_PORT:
182         bAppendPort = mScheme != "https";
183         break;
184 
185     case DEFAULT_FTP_PORT:
186         bAppendPort = mScheme != "ftp";
187         break;
188     }
189     if ( bAppendPort )
190     {
191         aBuf.append( ":" );
192         aBuf.append( mPort );
193     }
194     aBuf.append( mPath );
195 
196     mURI = aBuf.makeStringAndClear();
197 }
198 
GetPathBaseName() const199 OUString NeonUri::GetPathBaseName () const
200 {
201     sal_Int32 nPos = mPath.lastIndexOf ('/');
202     sal_Int32 nTrail = 0;
203     if (nPos == mPath.getLength () - 1)
204     {
205         // Trailing slash found. Skip.
206         nTrail = 1;
207         nPos = mPath.lastIndexOf ('/', nPos);
208     }
209     if (nPos != -1)
210     {
211         OUString aTemp(
212             mPath.copy (nPos + 1, mPath.getLength () - nPos - 1 - nTrail) );
213 
214         // query, fragment present?
215         nPos = aTemp.indexOf( '?' );
216         if ( nPos == -1 )
217             nPos = aTemp.indexOf( '#' );
218 
219         if ( nPos != -1 )
220             aTemp = aTemp.copy( 0, nPos );
221 
222         return aTemp;
223     }
224     else
225         return "/";
226 }
227 
operator ==(const NeonUri & rOther) const228 bool NeonUri::operator== ( const NeonUri & rOther ) const
229 {
230     return ( mURI == rOther.mURI );
231 }
232 
GetPathBaseNameUnescaped() const233 OUString NeonUri::GetPathBaseNameUnescaped () const
234 {
235     return unescape( GetPathBaseName() );
236 }
237 
AppendPath(std::u16string_view rPath)238 void NeonUri::AppendPath (std::u16string_view rPath)
239 {
240     if (mPath.lastIndexOf ('/') != mPath.getLength () - 1)
241         mPath += "/";
242 
243     mPath += rPath;
244     calculateURI ();
245 };
246 
247 // static
escapeSegment(const OUString & segment)248 OUString NeonUri::escapeSegment( const OUString& segment )
249 {
250     return rtl::Uri::encode( segment,
251                              rtl_UriCharClassPchar,
252                              rtl_UriEncodeIgnoreEscapes,
253                              RTL_TEXTENCODING_UTF8 );
254 }
255 
256 // static
unescape(const OUString & segment)257 OUString NeonUri::unescape( const OUString& segment )
258 {
259     return rtl::Uri::decode( segment,
260                              rtl_UriDecodeWithCharset,
261                              RTL_TEXTENCODING_UTF8 );
262 }
263 
264 // static
makeConnectionEndPointString(const OUString & rHostName,int nPort)265 OUString NeonUri::makeConnectionEndPointString(
266                                 const OUString & rHostName, int nPort )
267 {
268     OUStringBuffer aBuf;
269 
270     // Is host a numeric IPv6 address?
271     if ( ( rHostName.indexOf( ':' ) != -1 ) &&
272          ( rHostName[ 0 ] != '[' ) )
273     {
274         aBuf.append( "[" );
275         aBuf.append( rHostName );
276         aBuf.append( "]" );
277     }
278     else
279     {
280         aBuf.append( rHostName );
281     }
282 
283     if ( ( nPort != DEFAULT_HTTP_PORT ) && ( nPort != DEFAULT_HTTPS_PORT ) )
284     {
285         aBuf.append( ":" );
286         aBuf.append( static_cast<sal_Int32>(nPort) );
287     }
288     return aBuf.makeStringAndClear();
289 }
290 
291 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
292