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