XRootD
Loading...
Searching...
No Matches
XrdClURL.cc
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2011-2012 by European Organization for Nuclear Research (CERN)
3// Author: Lukasz Janyst <ljanyst@cern.ch>
4//------------------------------------------------------------------------------
5// XRootD is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// XRootD is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
17//------------------------------------------------------------------------------
18
19#include "XrdCl/XrdClLog.hh"
22#include "XrdCl/XrdClURL.hh"
23#include "XrdCl/XrdClUtils.hh"
24#include "XrdOuc/XrdOucUtils.hh"
27
28#include <cstdlib>
29#include <cctype>
30#include <vector>
31#include <sstream>
32#include <algorithm>
33
34namespace XrdCl
35{
36 //----------------------------------------------------------------------------
37 // Constructor
38 //----------------------------------------------------------------------------
40 pPort( 1094 )
41 {
42 }
43
44 //----------------------------------------------------------------------------
45 // Constructor
46 //----------------------------------------------------------------------------
47 URL::URL( const std::string &url ):
48 pPort( 1094 )
49 {
50 FromString( url );
51 }
52
53 URL::URL( const char *url ) : pPort( 1094 )
54 {
55 FromString( url );
56 }
57
58 //----------------------------------------------------------------------------
59 // Parse URL - it is rather trivial and horribly slow but probably there
60 // is not need to have anything more fancy
61 //----------------------------------------------------------------------------
62 bool URL::FromString( const std::string &url )
63 {
64 Log *log = DefaultEnv::GetLog();
65
66 Clear();
67
68 if( url.length() == 0 )
69 {
70 log->Error( UtilityMsg, "The given URL is empty" );
71 return false;
72 }
73
74 //--------------------------------------------------------------------------
75 // Extract the protocol, assume file:// if none found
76 //--------------------------------------------------------------------------
77 size_t pos = url.find( "://" );
78
79 std::string current;
80 if( pos != std::string::npos )
81 {
82 pProtocol = url.substr( 0, pos );
83 current = url.substr( pos+3 );
84 }
85 else if( url[0] == '/' )
86 {
87 pProtocol = "file";
88 current = url;
89 }
90 else if( url[0] == '-' )
91 {
92 pProtocol = "stdio";
93 current = "-";
94 pPort = 0;
95 }
96 else
97 {
98 pProtocol = "root";
99 current = url;
100 }
101
102 //--------------------------------------------------------------------------
103 // If the protocol is HTTP or HTTPS, change the default port number
104 //--------------------------------------------------------------------------
105 if (pProtocol == "http") {
106 pPort = 80;
107 }
108 if (pProtocol == "https") {
109 pPort = 443;
110 }
111
112 //--------------------------------------------------------------------------
113 // Extract host info and path
114 //--------------------------------------------------------------------------
115 std::string path;
116 std::string hostInfo;
117
118 if( pProtocol == "stdio" )
119 path = current;
120 else if( pProtocol == "file")
121 {
122 if( current[0] == '/' )
123 current = "localhost" + current;
124 pos = current.find( '/' );
125 if( pos == std::string::npos )
126 hostInfo = current;
127 else
128 {
129 hostInfo = current.substr( 0, pos );
130 path = current.substr( pos );
131 }
132 }
133 else
134 {
135 pos = current.find( '/' );
136 if( pos == std::string::npos )
137 hostInfo = current;
138 else
139 {
140 hostInfo = current.substr( 0, pos );
141 path = current.substr( pos+1 );
142 }
143 }
144
145 if( !ParseHostInfo( hostInfo ) )
146 {
147 Clear();
148 return false;
149 }
150
151 if( !ParsePath( path ) )
152 {
153 Clear();
154 return false;
155 }
156
157 ComputeURL();
158
159 //--------------------------------------------------------------------------
160 // Dump the url
161 //--------------------------------------------------------------------------
162 std::string urlLog = url;
163 if( unlikely(log->GetLevel() >= Log::DumpMsg)) {
164 urlLog = obfuscateAuth(urlLog);
165 }
166 log->Dump( UtilityMsg,
167 "URL: %s\n"
168 "Protocol: %s\n"
169 "User Name: %s\n"
170 "Password: %s\n"
171 "Host Name: %s\n"
172 "Port: %d\n"
173 "Path: %s\n",
174 urlLog.c_str(), pProtocol.c_str(), pUserName.c_str(),
175 pPassword.c_str(), pHostName.c_str(), pPort, pPath.c_str() );
176 return true;
177 }
178
179 //----------------------------------------------------------------------------
180 // Parse host info
181 //----------------------------------------------------------------------------
182 bool URL::ParseHostInfo( const std::string hostInfo )
183 {
184 if( pProtocol == "stdio" )
185 return true;
186
187 if( pProtocol.empty() || hostInfo.empty() )
188 return false;
189
190 size_t pos = hostInfo.find( "@" );
191 std::string hostPort;
192
193 //--------------------------------------------------------------------------
194 // We have found username-password
195 //--------------------------------------------------------------------------
196 if( pos != std::string::npos )
197 {
198 std::string userPass = hostInfo.substr( 0, pos );
199 hostPort = hostInfo.substr( pos+1 );
200 pos = userPass.find( ":" );
201
202 //------------------------------------------------------------------------
203 // It's both username and password
204 //------------------------------------------------------------------------
205 if( pos != std::string::npos )
206 {
207 pUserName = userPass.substr( 0, pos );
208 pPassword = userPass.substr( pos+1 );
209 }
210 //------------------------------------------------------------------------
211 // It's just the user name
212 //------------------------------------------------------------------------
213 else
214 pUserName = userPass;
215 }
216
217 //--------------------------------------------------------------------------
218 // No username-password
219 //--------------------------------------------------------------------------
220 else
221 hostPort = hostInfo;
222
223 //--------------------------------------------------------------------------
224 // Deal with hostname - IPv6 encoded address RFC 2732
225 //--------------------------------------------------------------------------
226 if( hostPort.length() >= 3 && hostPort[0] == '[' )
227 {
228 pos = hostPort.find( "]" );
229 if( pos != std::string::npos )
230 {
231 pHostName = hostPort.substr( 0, pos+1 );
232 hostPort.erase( 0, pos+2 );
233
234 //----------------------------------------------------------------------
235 // Check if we're IPv6 encoded IPv4
236 //----------------------------------------------------------------------
237 pos = pHostName.find( "." );
238 const size_t pos2 = pHostName.find( "[::" );
239 if( pos != std::string::npos && pos2 != std::string::npos )
240 {
241 std::string hl = pHostName;
242 std::transform(hl.begin(), hl.end(), hl.begin(),
243 [](unsigned char c){ return std::tolower(c); });
244 const size_t pos3 = hl.find( "[::ffff:" );
245 if ( pos3 != std::string::npos )
246 {
247 pHostName.erase( 0, 8 );
248 pHostName.erase( pHostName.length()-1, 1 );
249 }
250 else
251 {
252 pHostName.erase( 0, 3 );
253 pHostName.erase( pHostName.length()-1, 1 );
254 }
255 }
256 }
257 }
258 else
259 {
260 pos = hostPort.find( ":" );
261 if( pos != std::string::npos )
262 {
263 pHostName = hostPort.substr( 0, pos );
264 hostPort.erase( 0, pos+1 );
265 }
266 else
267 {
268 pHostName = hostPort;
269 hostPort = "";
270 }
271 if( pHostName.empty() )
272 return false;
273 }
274
275 //--------------------------------------------------------------------------
276 // Deal with port number
277 //--------------------------------------------------------------------------
278 if( !hostPort.empty() )
279 {
280 char *result;
281 pPort = ::strtol( hostPort.c_str(), &result, 10 );
282 if( *result != '\0' || pPort < 0 || pPort > 65535 )
283 return false;
284 }
285
286 ComputeHostId();
287 return true;
288 }
289
290 //----------------------------------------------------------------------------
291 // Parse path
292 //----------------------------------------------------------------------------
293 bool URL::ParsePath( const std::string &path )
294 {
295 size_t pos = path.find( "?" );
296 if( pos != std::string::npos )
297 {
298 pPath = path.substr( 0, pos );
299 SetParams( path.substr( pos+1, path.length() ) );
300 }
301 else
302 pPath = path;
303
304 if( !pPath.empty() )
305 {
306 std::string::iterator back = pPath.end() - 1;
307 if( pProtocol == "file" && *back == '/' )
308 pPath.erase( back );
309 }
310
311 ComputeURL();
312 return true;
313 }
314
315 //----------------------------------------------------------------------------
316 // Get path with params
317 //----------------------------------------------------------------------------
318 std::string URL::GetPathWithParams() const
319 {
320 std::ostringstream o;
321 if( !pPath.empty() )
322 o << pPath;
323
324 o << GetParamsAsString();
325 return o.str();
326 }
327
328 //------------------------------------------------------------------------
330 //------------------------------------------------------------------------
332 {
333 std::ostringstream o;
334 if( !pPath.empty() )
335 o << pPath;
336
337 o << GetParamsAsString( true );
338 return o.str();
339 }
340
341 //------------------------------------------------------------------------
343 //------------------------------------------------------------------------
344 std::string URL::GetLocation() const
345 {
346 std::ostringstream o;
347 o << pProtocol << "://";
348 if( pProtocol == "file" )
349 o << pHostName;
350 else
351 o << pHostName << ":" << pPort << "/";
352 o << pPath;
353 return o.str();
354 }
355
356 //------------------------------------------------------------------------
357 // Get the URL params as string
358 //------------------------------------------------------------------------
359 std::string URL::GetParamsAsString() const
360 {
361 return GetParamsAsString( false );
362 }
363
364 //------------------------------------------------------------------------
365 // Get the login token if present in the opaque info
366 //------------------------------------------------------------------------
367 std::string URL::GetLoginToken() const
368 {
369 auto itr = pParams.find( "xrd.logintoken" );
370 if( itr == pParams.end() )
371 return "";
372 return itr->second;
373 }
374
375 //------------------------------------------------------------------------
377 //------------------------------------------------------------------------
378 std::string URL::GetParamsAsString( bool filter ) const
379 {
380 if( pParams.empty() )
381 return "";
382
383 std::ostringstream o;
384 o << "?";
385 ParamsMap::const_iterator it;
386 for( it = pParams.begin(); it != pParams.end(); ++it )
387 {
388 // we filter out client specific parameters
389 if( filter && it->first.compare( 0, 6, "xrdcl." ) == 0 )
390 continue;
391 if( it != pParams.begin() ) o << "&";
392 o << it->first << "=" << it->second;
393 }
394 std::string ret = o.str();
395 if( ret == "?" ) ret.clear();
396 return ret;
397 }
398
399 //------------------------------------------------------------------------
400 // Set params
401 //------------------------------------------------------------------------
402 void URL::SetParams( const std::string &params )
403 {
404 pParams.clear();
405 std::string p = params;
406
407 if( p.empty() )
408 return;
409
410 if( p[0] == '?' )
411 p.erase( 0, 1 );
412
413 std::vector<std::string> paramsVect;
414 std::vector<std::string>::iterator it;
415 Utils::splitString( paramsVect, p, "&" );
416 for( it = paramsVect.begin(); it != paramsVect.end(); ++it )
417 {
418 if( it->empty() ) continue;
419 size_t qpos = it->find( '?' );
420 if( qpos != std::string::npos ) // we have login token
421 {
422 pParams["xrd.logintoken"] = it->substr( qpos + 1 );
423 it->erase( qpos );
424 }
425 size_t pos = it->find( "=" );
426 if( pos == std::string::npos )
427 pParams[*it] = "";
428 else
429 pParams[it->substr(0, pos)] = it->substr( pos+1, it->length() );
430 }
431 }
432
433 //----------------------------------------------------------------------------
434 // Clear the fields
435 //----------------------------------------------------------------------------
437 {
438 pHostId.clear();
439 pProtocol.clear();
440 pUserName.clear();
441 pPassword.clear();
442 pHostName.clear();
443 pPort = 1094;
444 pPath.clear();
445 pParams.clear();
446 pURL.clear();
447 }
448
449 //----------------------------------------------------------------------------
450 // Check validity
451 //----------------------------------------------------------------------------
452 bool URL::IsValid() const
453 {
454 if( pProtocol.empty() )
455 return false;
456 if( pProtocol == "file" && pPath.empty() )
457 return false;
458 if( pProtocol == "stdio" && pPath != "-" )
459 return false;
460 if( pProtocol != "file" && pProtocol != "stdio" && pHostName.empty() )
461 return false;
462 return true;
463 }
464
465 bool URL::IsMetalink() const
466 {
467 Env *env = DefaultEnv::GetEnv();
468 int mlProcessing = DefaultMetalinkProcessing;
469 env->GetInt( "MetalinkProcessing", mlProcessing );
470 if( !mlProcessing ) return false;
471 return PathEndsWith( ".meta4" ) || PathEndsWith( ".metalink" );
472 }
473
474 bool URL::IsLocalFile() const
475 {
476 return pProtocol == "file" && pHostName == "localhost";
477 }
478
479 //------------------------------------------------------------------------
480 // Does the protocol indicate encryption
481 //------------------------------------------------------------------------
482 bool URL::IsSecure() const
483 {
484 return ( pProtocol == "roots" || pProtocol == "xroots" );
485 }
486
487 //------------------------------------------------------------------------
488 // Is the URL used in TPC context
489 //------------------------------------------------------------------------
490 bool URL::IsTPC() const
491 {
492 ParamsMap::const_iterator itr = pParams.find( "xrdcl.intent" );
493 if( itr != pParams.end() )
494 return itr->second == "tpc";
495 return false;
496 }
497
498 std::string URL::GetObfuscatedURL() const {
499 return obfuscateAuth(pURL);
500 }
501
502 bool URL::PathEndsWith(const std::string & sufix) const
503 {
504 if (sufix.size() > pPath.size()) return false;
505 return std::equal(sufix.rbegin(), sufix.rend(), pPath.rbegin() );
506 }
507
508 //------------------------------------------------------------------------
509 //Get the host part of the URL (user:password\@host:port) plus channel
510 //specific CGI (xrdcl.identity & xrd.gsiusrpxy)
511 //------------------------------------------------------------------------
512 std::string URL::GetChannelId() const
513 {
514 std::string ret = pProtocol + "://" + pHostId + "/";
515 bool hascgi = false;
516
517 std::string keys[] = { "xrdcl.intent",
518 "xrd.gsiusrpxy",
519 "xrd.gsiusrcrt",
520 "xrd.gsiusrkey",
521 "xrd.sss",
522 "xrd.k5ccname" };
523 size_t size = sizeof( keys ) / sizeof( std::string );
524
525 for( size_t i = 0; i < size; ++i )
526 {
527 ParamsMap::const_iterator itr = pParams.find( keys[i] );
528 if( itr != pParams.end() )
529 {
530 ret += hascgi ? '&' : '?';
531 ret += itr->first;
532 ret += '=';
533 ret += itr->second;
534 hascgi = true;
535 }
536 }
537
538 return ret;
539 }
540
541 //----------------------------------------------------------------------------
542 // Recompute the host id
543 //----------------------------------------------------------------------------
544 void URL::ComputeHostId()
545 {
546 std::ostringstream o;
547 if( !pUserName.empty() )
548 {
549 o << pUserName;
550 if( !pPassword.empty() )
551 o << ":" << pPassword;
552 o << "@";
553 }
554 if( pProtocol == "file" )
555 o << pHostName;
556 else
557 o << pHostName << ":" << pPort;
558 pHostId = o.str();
559 }
560
561 //----------------------------------------------------------------------------
562 // Recreate the url
563 //----------------------------------------------------------------------------
564 void URL::ComputeURL()
565 {
566 if( !IsValid() ) {
567 pURL = "";
568 }
569
570 std::ostringstream o;
571 if( !pProtocol.empty() )
572 o << pProtocol << "://";
573
574 if( !pUserName.empty() )
575 {
576 o << pUserName;
577 if( !pPassword.empty() )
578 o << ":" << pPassword;
579 o << "@";
580 }
581
582 if( !pHostName.empty() )
583 {
584 if( pProtocol == "file" )
585 o << pHostName;
586 else
587 o << pHostName << ":" << pPort << "/";
588 }
589
590 o << GetPathWithParams();
591
592 pURL = o.str();
593 }
594}
#define unlikely(x)
std::string obfuscateAuth(const std::string &input)
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
bool GetInt(const std::string &key, int &value)
Definition XrdClEnv.cc:89
Handle diagnostics.
Definition XrdClLog.hh:101
@ DumpMsg
print details of the request and responses
Definition XrdClLog.hh:113
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition XrdClLog.cc:231
LogLevel GetLevel() const
Get the log level.
Definition XrdClLog.hh:258
void Dump(uint64_t topic, const char *format,...)
Print a dump message.
Definition XrdClLog.cc:299
std::string GetChannelId() const
Definition XrdClURL.cc:512
bool IsMetalink() const
Is it a URL to a metalink.
Definition XrdClURL.cc:465
bool FromString(const std::string &url)
Parse a string and fill the URL fields.
Definition XrdClURL.cc:62
void SetParams(const std::string &params)
Set params.
Definition XrdClURL.cc:402
URL()
Default constructor.
Definition XrdClURL.cc:39
std::string GetPathWithFilteredParams() const
Get the path with params, filteres out 'xrdcl.'.
Definition XrdClURL.cc:331
std::string GetPathWithParams() const
Get the path with params.
Definition XrdClURL.cc:318
std::string GetObfuscatedURL() const
Get the URL with authz information obfuscated.
Definition XrdClURL.cc:498
std::string GetLocation() const
Get location (protocol://host:port/path)
Definition XrdClURL.cc:344
bool IsLocalFile() const
Definition XrdClURL.cc:474
std::string GetParamsAsString() const
Get the URL params as string.
Definition XrdClURL.cc:359
bool IsSecure() const
Does the protocol indicate encryption.
Definition XrdClURL.cc:482
bool IsValid() const
Is the url valid.
Definition XrdClURL.cc:452
void Clear()
Clear the url.
Definition XrdClURL.cc:436
bool IsTPC() const
Is the URL used in TPC context.
Definition XrdClURL.cc:490
std::string GetLoginToken() const
Get the login token if present in the opaque info.
Definition XrdClURL.cc:367
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition XrdClUtils.hh:56
const int DefaultMetalinkProcessing
const uint64_t UtilityMsg