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