Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/downloader/urlSpec.cxx

Go to the documentation of this file.
00001 // Filename: urlSpec.cxx
00002 // Created by:  drose (24Sep02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "urlSpec.h"
00020 
00021 #include <ctype.h>
00022 
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: URLSpec::Constructor
00026 //       Access: Published
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 URLSpec::
00030 URLSpec() {
00031   _port = 0;
00032   _flags = 0;
00033   _scheme_end = 0;
00034   _username_start = 0;
00035   _username_end = 0;
00036   _server_start = 0;
00037   _server_end = 0;
00038   _port_start = 0;
00039   _port_end = 0;
00040   _path_start = 0;
00041   _path_end = 0;
00042   _query_start = 0;
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: URLSpec::Copy Assignment Operator
00047 //       Access: Published
00048 //  Description:
00049 ////////////////////////////////////////////////////////////////////
00050 void URLSpec::
00051 operator = (const URLSpec &copy) {
00052   _url = copy._url;
00053   _port = copy._port;
00054   _flags = copy._flags;
00055   _scheme_end = copy._scheme_end;
00056   _username_start = copy._username_start;
00057   _username_end = copy._username_end;
00058   _server_start = copy._server_start;
00059   _server_end = copy._server_end;
00060   _port_start = copy._port_start;
00061   _port_end = copy._port_end;
00062   _path_start = copy._path_start;
00063   _path_end = copy._path_end;
00064   _query_start = copy._query_start;
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: URLSpec::get_scheme
00069 //       Access: Published
00070 //  Description: Returns the scheme specified by the URL, or empty
00071 //               string if no scheme is specified.
00072 ////////////////////////////////////////////////////////////////////
00073 string URLSpec::
00074 get_scheme() const {
00075   if (has_scheme()) {
00076     return _url.substr(0, _scheme_end);
00077   }
00078   return string();
00079 }
00080 
00081 ////////////////////////////////////////////////////////////////////
00082 //     Function: URLSpec::get_port
00083 //       Access: Published
00084 //  Description: Returns the port number specified by the URL, or the
00085 //               default port if not specified.
00086 ////////////////////////////////////////////////////////////////////
00087 int URLSpec::
00088 get_port() const {
00089   if (has_port()) {
00090     return _port;
00091   }
00092   string scheme = get_scheme();
00093   if (scheme == "https") {
00094     return 443;
00095 
00096   } else { // == "http"
00097     return 80;
00098   }
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: URLSpec::get_server_and_port
00103 //       Access: Published
00104 //  Description: Returns a string consisting of the server name,
00105 //               followed by a colon, followed by the port number.  If
00106 //               the port number is not explicitly given in the URL,
00107 //               this string will include the implicit port number.
00108 ////////////////////////////////////////////////////////////////////
00109 string URLSpec::
00110 get_server_and_port() const {
00111   if (has_port()) {
00112     return _url.substr(_server_start, _port_end - _server_start);
00113   }
00114   ostringstream strm;
00115   strm << get_server() << ":" << get_port();
00116   return strm.str();
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: URLSpec::get_path
00121 //       Access: Published
00122 //  Description: Returns the path specified by the URL, or "/" if no
00123 //               path is specified.
00124 ////////////////////////////////////////////////////////////////////
00125 string URLSpec::
00126 get_path() const {
00127   if (has_path()) {
00128     return _url.substr(_path_start, _path_end - _path_start);
00129   }
00130   return "/";
00131 }
00132 
00133 ////////////////////////////////////////////////////////////////////
00134 //     Function: URLSpec::set_scheme
00135 //       Access: Published
00136 //  Description: Replaces the scheme part of the URL specification.
00137 ////////////////////////////////////////////////////////////////////
00138 void URLSpec::
00139 set_scheme(const string &scheme) {
00140   int length_adjust;
00141 
00142   // The scheme is always converted to lowercase.
00143   string lc_scheme;
00144   lc_scheme.reserve(scheme.length());
00145   for (string::const_iterator si = scheme.begin(); si != scheme.end(); ++si) {
00146     lc_scheme += tolower(*si);
00147   }
00148 
00149   if (lc_scheme.empty()) {
00150     // Remove the scheme specification.
00151     if (!has_scheme()) {
00152       return;
00153     }
00154     // Increment over the trailing colon so we can remove that too.
00155     _scheme_end++;
00156     length_adjust = -(int)_scheme_end;
00157     _url = _url.substr(_scheme_end);
00158     _flags &= ~F_has_scheme;
00159 
00160   } else if (!has_scheme()) {
00161     // Insert a new scheme specification.  The user may or may not
00162     // have specified a colon.
00163     if (lc_scheme[lc_scheme.length() - 1] == ':') {
00164       length_adjust = lc_scheme.length();
00165       _url = lc_scheme + _url;
00166 
00167     } else {
00168       length_adjust = lc_scheme.length() + 1;
00169       _url = lc_scheme + ":" + _url;
00170     }
00171 
00172     // Since the length_adjust flag, above, now accounts for the
00173     // colon, subtract one from _scheme_end (which should not include
00174     // the colon).
00175     _scheme_end--;
00176     _flags |= F_has_scheme;
00177 
00178   } else {
00179     // Replace the existing scheme specification.  Since the existing
00180     // scheme will already be trailed by a colon, remove the colon
00181     // from the string if the user appended one.
00182     if (lc_scheme[lc_scheme.length() - 1] == ':') {
00183       lc_scheme = lc_scheme.substr(0, lc_scheme.length() - 1);
00184     }
00185 
00186     int old_length = (int)_scheme_end;
00187     length_adjust = scheme.length() - old_length;
00188     _url = lc_scheme + _url.substr(_scheme_end);
00189   }
00190 
00191   _scheme_end += length_adjust;
00192   _username_start += length_adjust;
00193   _username_end += length_adjust;
00194   _server_start += length_adjust;
00195   _server_end += length_adjust;
00196   _port_start += length_adjust;
00197   _port_end += length_adjust;
00198   _path_start += length_adjust;
00199   _path_end += length_adjust;
00200   _query_start += length_adjust;
00201 }
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: URLSpec::set_authority
00205 //       Access: Published
00206 //  Description: Replaces the authority part of the URL specification.
00207 //               This includes the username, server, and port.
00208 ////////////////////////////////////////////////////////////////////
00209 void URLSpec::
00210 set_authority(const string &authority) {
00211   int length_adjust;
00212   int extra_slash_adjust = 0;
00213 
00214   if (authority.empty()) {
00215     // Remove the authority specification.
00216     if (!has_authority()) {
00217       return;
00218     }
00219     _username_start -= 2;
00220     length_adjust = -((int)_port_end - (int)_username_start);
00221     _url = _url.substr(0, _username_start) + _url.substr(_port_end);
00222     _flags &= ~(F_has_authority | F_has_username | F_has_server | F_has_port);
00223 
00224     _username_end = _username_start;
00225     _server_start = _username_start;
00226     _server_end = _username_start;
00227     _port_start = _username_start;
00228 
00229   } else if (!has_authority()) {
00230     // Insert a new authority specification.
00231     length_adjust = authority.length() + 2;
00232 
00233     string extra_slash;
00234     if (has_path() && _url[_path_start] != '/') {
00235       // If we have a path but it doesn't begin with a slash, it should.
00236       extra_slash = '/';
00237       extra_slash_adjust = 1;
00238     }
00239     _url = _url.substr(0, _username_start) + "//" + authority + extra_slash + _url.substr(_port_end);
00240     _flags |= F_has_authority;
00241     _username_start += 2;
00242 
00243   } else {
00244     // Replace an existing authority specification.
00245     int old_length = (int)_port_end - (int)_username_start;
00246     length_adjust = authority.length() - old_length;
00247     _url = _url.substr(0, _username_start) + authority + _url.substr(_port_end);
00248   }
00249 
00250   _port_end += length_adjust;
00251   _path_start += length_adjust;
00252   _path_end += length_adjust + extra_slash_adjust;
00253   _query_start += length_adjust + extra_slash_adjust;
00254 
00255   parse_authority();
00256 }
00257 
00258 ////////////////////////////////////////////////////////////////////
00259 //     Function: URLSpec::set_username
00260 //       Access: Published
00261 //  Description: Replaces the username part of the URL specification.
00262 ////////////////////////////////////////////////////////////////////
00263 void URLSpec::
00264 set_username(const string &username) {
00265   if (username.empty() && !has_authority()) {
00266     return;
00267   }
00268   string authority;
00269 
00270   if (!username.empty()) {
00271     authority = username + "@";
00272   }
00273   authority += get_server();
00274   if (has_port()) {
00275     authority += ":";
00276     authority += get_port_str();
00277   }
00278 
00279   set_authority(authority);
00280 }
00281 
00282 ////////////////////////////////////////////////////////////////////
00283 //     Function: URLSpec::set_server
00284 //       Access: Published
00285 //  Description: Replaces the server part of the URL specification.
00286 ////////////////////////////////////////////////////////////////////
00287 void URLSpec::
00288 set_server(const string &server) {
00289   if (server.empty() && !has_authority()) {
00290     return;
00291   }
00292   string authority;
00293 
00294   if (has_username()) {
00295     authority = get_username() + "@";
00296   }
00297   authority += server;
00298   if (has_port()) {
00299     authority += ":";
00300     authority += get_port_str();
00301   }
00302 
00303   set_authority(authority);
00304 }
00305 
00306 ////////////////////////////////////////////////////////////////////
00307 //     Function: URLSpec::set_port
00308 //       Access: Published
00309 //  Description: Replaces the port part of the URL specification.
00310 ////////////////////////////////////////////////////////////////////
00311 void URLSpec::
00312 set_port(const string &port) {
00313   if (port.empty() && !has_authority()) {
00314     return;
00315   }
00316   string authority;
00317 
00318   if (has_username()) {
00319     authority = get_username() + "@";
00320   }
00321   authority += get_server();
00322 
00323   if (!port.empty()) {
00324     authority += ":";
00325     authority += port;
00326   }
00327 
00328   set_authority(authority);
00329 }
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: URLSpec::set_port
00333 //       Access: Published
00334 //  Description: Replaces the port part of the URL specification,
00335 //               given a numeric port number.
00336 ////////////////////////////////////////////////////////////////////
00337 void URLSpec::
00338 set_port(int port) {
00339   ostringstream str;
00340   str << port;
00341   set_port(str.str());
00342 }
00343 
00344 ////////////////////////////////////////////////////////////////////
00345 //     Function: URLSpec::set_server_and_port
00346 //       Access: Published
00347 //  Description: Replaces the server and port parts of the URL
00348 //               specification simultaneously.  The input string
00349 //               should be of the form "server:port", or just
00350 //               "server" to make the port number implicit.
00351 ////////////////////////////////////////////////////////////////////
00352 void URLSpec::
00353 set_server_and_port(const string &server_and_port) {
00354   if (server_and_port.empty() && !has_authority()) {
00355     return;
00356   }
00357   string authority;
00358 
00359   if (has_username()) {
00360     authority = get_username() + "@";
00361   }
00362   authority += server_and_port;
00363   set_authority(authority);
00364 }
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: URLSpec::set_path
00368 //       Access: Published
00369 //  Description: Replaces the path part of the URL specification.
00370 ////////////////////////////////////////////////////////////////////
00371 void URLSpec::
00372 set_path(const string &path) {
00373   int length_adjust;
00374 
00375   if (path.empty()) {
00376     // Remove the path specification.
00377     if (!has_path()) {
00378       return;
00379     }
00380     length_adjust = -((int)_path_end - (int)_path_start);
00381     _url = _url.substr(0, _path_start) + _url.substr(_path_end);
00382     _flags &= ~F_has_path;
00383 
00384   } else if (!has_path()) {
00385     // Insert a new path specification.
00386     string cpath = path;
00387     if (cpath[0] != '/') {
00388       // Paths must always begin with a slash.
00389       cpath = '/' + cpath;
00390     }
00391     length_adjust = cpath.length();
00392 
00393     _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
00394     _flags |= F_has_path;
00395 
00396   } else {
00397     // Replace an existing path specification.
00398     string cpath = path;
00399     if (cpath[0] != '/') {
00400       // Paths must always begin with a slash.
00401       cpath = '/' + cpath;
00402     }
00403     int old_length = (int)_path_end - (int)_path_start;
00404     length_adjust = cpath.length() - old_length;
00405     _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
00406   }
00407 
00408   _path_end += length_adjust;
00409   _query_start += length_adjust;
00410 }
00411 
00412 ////////////////////////////////////////////////////////////////////
00413 //     Function: URLSpec::set_query
00414 //       Access: Published
00415 //  Description: Replaces the query part of the URL specification.
00416 ////////////////////////////////////////////////////////////////////
00417 void URLSpec::
00418 set_query(const string &query) {
00419   if (query.empty()) {
00420     // Remove the query specification.
00421     if (!has_query()) {
00422       return;
00423     }
00424     _query_start--;
00425     _url = _url.substr(0, _query_start);
00426     _flags &= ~F_has_query;
00427 
00428   } else if (!has_query()) {
00429     // Insert a new query specification.
00430     _url = _url.substr(0, _query_start) + "?" + query;
00431     _flags |= F_has_query;
00432     _query_start++;
00433 
00434   } else {
00435     // Replace an existing query specification.
00436     _url = _url.substr(0, _query_start) + query;
00437   }
00438 }
00439 
00440 ////////////////////////////////////////////////////////////////////
00441 //     Function: URLSpec::set_url
00442 //       Access: Published
00443 //  Description: Completely replaces the URL with the indicated
00444 //               string.  If server_name_expected is true, it is a
00445 //               hint that an undecorated URL is probably a server
00446 //               name, not a local filename.
00447 ////////////////////////////////////////////////////////////////////
00448 void URLSpec::
00449 set_url(const string &url, bool server_name_expected) {
00450   _url = url;
00451   _flags = 0;
00452 
00453   if (url.empty()) {
00454     // No server name on an empty string.
00455     server_name_expected = false;
00456   }
00457 
00458   // First, replace backslashes with forward slashes, since this is a
00459   // common mistake among Windows users.
00460   size_t p;
00461   for (p = 0; p < _url.length(); p++) {
00462     if (_url[p] == '\\') {
00463       _url[p] = '/';
00464     }
00465   }
00466 
00467   // What have we got?
00468   _flags = 0;
00469   _port = 0;
00470 
00471   // Look for the scheme specification.
00472   size_t start = 0;
00473 
00474   _scheme_end = start;
00475   size_t next = _url.find_first_of(":/", start);
00476   if (next < _url.length() - 1 && _url.substr(next, 2) == ":/") {
00477     // We have a scheme.
00478     _flags |= F_has_scheme;
00479     _scheme_end = next;
00480 
00481     // Ensure the scheme is lowercase.
00482     for (size_t p = 0; p < _scheme_end; ++p) {
00483       _url[p] = tolower(_url[p]);
00484     }
00485 
00486     start = next + 1;
00487   }
00488 
00489   // Look for the authority specification, which may include any of
00490   // username, server, and/or port.
00491   _username_start = start;
00492   _username_end = start;
00493   _server_start = start;
00494   _server_end = start;
00495   _port_start = start;
00496   _port_end = start;
00497 
00498   // Try to determine if an authority is present.  It is will
00499   // generally be present if a scheme was present; also, we have a
00500   // hint passed in from the context as to whether we expect an
00501   // authority (e.g. a server name) to be present.
00502   bool has_authority = (has_scheme() || server_name_expected);
00503 
00504   // We also know we have an authority if the url contains two slashes
00505   // at this point.
00506   bool leading_slashes = 
00507     (start < _url.length() - 1 && _url.substr(start, 2) == "//");
00508   if (leading_slashes) {
00509     has_authority = true;
00510   }
00511 
00512   if (has_authority) {
00513     // Now that we know we have an authority, we should ensure there
00514     // are two slashes here, since there should be before the
00515     // authority.
00516     if (!leading_slashes) {
00517       if (start < _url.length() && _url[start] == '/') {
00518         // Well, at least we had one slash.  Double it.
00519         _url = _url.substr(0, start + 1) + _url.substr(start);
00520       } else {
00521         // No slashes at all.  Insert them.
00522         _url = _url.substr(0, start) + "//" + _url.substr(start);
00523       }
00524     }
00525 
00526     // Begin the actual authority specification.
00527     start += 2;
00528     _flags |= F_has_authority;
00529     _username_start = start;
00530     _port_end = _url.find_first_of("/?", start);
00531     if (_port_end == string::npos) {
00532       _port_end = _url.length();
00533     }
00534     parse_authority();
00535     start = _port_end;
00536   }
00537 
00538   // Everything up to the ?, if any, is the path.
00539   _path_start = start;
00540   _path_end = start;
00541   if (start < _url.length() && url[start] != '?') {
00542     // We have a path.
00543     _flags |= F_has_path;
00544     _path_start = start;
00545     _path_end = _url.find("?", _path_start);
00546     if (_path_end == string::npos) {
00547       _path_end = _url.length();
00548     }
00549     start = _path_end;
00550   }
00551 
00552   // Everything after the ? is the query.
00553   _query_start = start;
00554   if (start < _url.length()) {
00555     nassertv(_url[start] == '?');
00556     _flags |= F_has_query;
00557     _query_start++;
00558   }
00559 }
00560 
00561 ////////////////////////////////////////////////////////////////////
00562 //     Function: URLSpec::input
00563 //       Access: Published
00564 //  Description: 
00565 ////////////////////////////////////////////////////////////////////
00566 bool URLSpec::
00567 input(istream &in) {
00568   string url;
00569   in >> url;
00570   if (!in) {
00571     return false;
00572   }
00573   set_url(url);
00574   return true;
00575 }
00576 
00577 ////////////////////////////////////////////////////////////////////
00578 //     Function: URLSpec::output
00579 //       Access: Published
00580 //  Description: 
00581 ////////////////////////////////////////////////////////////////////
00582 void URLSpec::
00583 output(ostream &out) const {
00584   out << get_url();
00585 }
00586 
00587 ////////////////////////////////////////////////////////////////////
00588 //     Function: URLSpec::quote
00589 //       Access: Published, Static
00590 //  Description: Returns the source string with all "unsafe"
00591 //               characters quoted, making a string suitable for
00592 //               placing in a URL.  Letters, digits, and the
00593 //               underscore, comma, period, and hyphen characters, as
00594 //               well as any included in the safe string, are left
00595 //               alone; all others are converted to hex
00596 //               representation.
00597 ////////////////////////////////////////////////////////////////////
00598 string URLSpec::
00599 quote(const string &source, const string &safe) {
00600   ostringstream result;
00601   result << hex << setfill('0');
00602 
00603   for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
00604     char ch = (*si);
00605     switch (ch) {
00606     case '_':
00607     case ',':
00608     case '.':
00609     case '-':
00610       // Safe character.
00611       result << ch;
00612       break;
00613 
00614     default:
00615       if (isalnum(ch)) {
00616         // Letters and digits are safe.
00617         result << ch;
00618 
00619       } else if (safe.find(ch) != string::npos) {
00620         // If it's listed in "safe", it's safe.
00621         result << ch;
00622 
00623       } else {
00624         // Otherwise, escape it.
00625         result << '%' << setw(2) << (int)ch;
00626       }
00627     }
00628   }
00629 
00630   return result.str();
00631 }
00632 
00633 ////////////////////////////////////////////////////////////////////
00634 //     Function: URLSpec::quote_plus
00635 //       Access: Published, Static
00636 //  Description: Behaves like quote() with the additional behavior of
00637 //               replacing spaces with plus signs.
00638 ////////////////////////////////////////////////////////////////////
00639 string URLSpec::
00640 quote_plus(const string &source, const string &safe) {
00641   ostringstream result;
00642   result << hex << setfill('0');
00643 
00644   for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
00645     char ch = (*si);
00646     switch (ch) {
00647     case '_':
00648     case ',':
00649     case '.':
00650     case '-':
00651       // Safe character.
00652       result << ch;
00653       break;
00654 
00655     case ' ':
00656       result << '+';
00657       break;
00658 
00659     default:
00660       if (isalnum(ch)) {
00661         // Letters and digits are safe.
00662         result << ch;
00663 
00664       } else if (safe.find(ch) != string::npos) {
00665         // If it's listed in "safe", it's safe.
00666         result << ch;
00667 
00668       } else {
00669         // Otherwise, escape it.
00670         result << '%' << setw(2) << (int)ch;
00671       }
00672     }
00673   }
00674 
00675   return result.str();
00676 }
00677 
00678 ////////////////////////////////////////////////////////////////////
00679 //     Function: URLSpec::unquote
00680 //       Access: Published, Static
00681 //  Description: Reverses the operation of quote(): converts escaped
00682 //               characters of the form "%xx" to their ascii
00683 //               equivalent.
00684 ////////////////////////////////////////////////////////////////////
00685 string URLSpec::
00686 unquote(const string &source) {
00687   string result;
00688 
00689   size_t p = 0;
00690   while (p < source.length()) {
00691     if (source[p] == '%' && p + 2 < source.length()) {
00692       int hex = 0;
00693       p++;
00694       for (int i = 0; i < 2; i++) {
00695         int value;
00696         char ch = source[p + i];
00697         if (isdigit(ch)) {
00698           value = ch - '0';
00699         } else {
00700           value = tolower(ch) - 'a' + 10;
00701         }
00702         hex = (hex << 4) | value;
00703       }
00704       result += (char)hex;
00705       p += 2;
00706 
00707     } else {
00708       result += source[p];
00709       p++;
00710     }
00711   }
00712 
00713   return result;
00714 }
00715 
00716 ////////////////////////////////////////////////////////////////////
00717 //     Function: URLSpec::unquote_plus
00718 //       Access: Published, Static
00719 //  Description: Reverses the operation of quote_plus(): converts escaped
00720 //               characters of the form "%xx" to their ascii
00721 //               equivalent, and also converts plus signs to spaces.
00722 ////////////////////////////////////////////////////////////////////
00723 string URLSpec::
00724 unquote_plus(const string &source) {
00725   string result;
00726 
00727   size_t p = 0;
00728   while (p < source.length()) {
00729     if (source[p] == '%' && p + 2 < source.length()) {
00730       int hex = 0;
00731       p++;
00732       for (int i = 0; i < 2; i++) {
00733         int value;
00734         char ch = source[p + i];
00735         if (isdigit(ch)) {
00736           value = ch - '0';
00737         } else {
00738           value = tolower(ch) - 'a' + 10;
00739         }
00740         hex = (hex << 4) | value;
00741       }
00742       result += (char)hex;
00743       p += 2;
00744 
00745     } else if (source[p] == '+') {
00746       result += ' ';
00747       p++;
00748 
00749     } else {
00750       result += source[p];
00751       p++;
00752     }
00753   }
00754 
00755   return result;
00756 }
00757 
00758 ////////////////////////////////////////////////////////////////////
00759 //     Function: URLSpec::parse_authority
00760 //       Access: Private
00761 //  Description: Assumes _url[_username_start .. _port_end - 1] is
00762 //               the authority component if the URL, consisting of
00763 //               [username@]server[:port].  Parses out the three
00764 //               pieces and updates the various _start and _end
00765 //               parameters accordingly.
00766 ////////////////////////////////////////////////////////////////////
00767 void URLSpec::
00768 parse_authority() {
00769   _flags &= ~(F_has_username | F_has_server | F_has_port);
00770 
00771   if (!has_authority()) {
00772     return;
00773   }
00774 
00775   // Assume we don't have a username or port unless we find them.
00776   _username_end = _username_start;
00777   _port_start = _port_end;
00778 
00779   // We assume we have a server, even if it becomes the empty string.
00780   _flags |= F_has_server;
00781   _server_start = _username_start;
00782   _server_end = _port_end;
00783 
00784   // Is there a username?
00785   size_t at_sign = _url.find('@', _username_start);
00786   if (at_sign < _port_end) {
00787     // We have a username.
00788     _flags |= F_has_username;
00789     _username_end = at_sign;
00790     _server_start = at_sign + 1;
00791   }
00792 
00793   // Is there a port?
00794   size_t colon = _url.find(':', _server_start);
00795   if (colon < _port_end) {
00796     // Yep.
00797     _flags |= F_has_port;
00798     _server_end = colon;
00799     _port_start = colon + 1;
00800         
00801     // Decode the port into an integer.  Don't bother to error
00802     // check if it's not really an integer.
00803     string port_str = _url.substr(_port_start, _port_end - _port_start);
00804     _port = atoi(port_str.c_str());
00805   }
00806 
00807   // Make sure the server name is lowercase only.
00808   for (size_t si = _server_start; si != _server_end; ++si) {
00809     _url[si] = tolower(_url[si]);
00810   }
00811 
00812   // Also make sure the server name doesn't end with a dot.  It's
00813   // happened!  Silly users.
00814   if (_server_end > _server_start && _url[_server_end - 1] == '.') {
00815     _url = _url.substr(0, _server_end - 1) + _url.substr(_server_end);
00816     _server_end--;
00817     _port_start--;
00818     _port_end--;
00819     _path_start--;
00820     _path_end--;
00821     _query_start--;
00822   }
00823 }

Generated on Fri May 2 00:36:52 2003 for Panda by doxygen1.3