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

panda/src/downloader/httpAuthorization.cxx

Go to the documentation of this file.
00001 // Filename: httpAuthorization.cxx
00002 // Created by:  drose (22Oct02)
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 "httpAuthorization.h"
00020 #include "httpChannel.h"
00021 #include "urlSpec.h"
00022 
00023 #ifdef HAVE_SSL
00024 
00025 static const char base64_table[64] = {
00026   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
00027   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
00028   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
00029   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
00030   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
00031   'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
00032   'w', 'x', 'y', 'z', '0', '1', '2', '3',
00033   '4', '5', '6', '7', '8', '9', '+', '/',
00034 };
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: HTTPAuthorization::Constructor
00038 //       Access: Protected
00039 //  Description: 
00040 ////////////////////////////////////////////////////////////////////
00041 HTTPAuthorization::
00042 HTTPAuthorization(const HTTPAuthorization::Tokens &tokens, 
00043                   const URLSpec &url, bool is_proxy) {
00044   Tokens::const_iterator ti;
00045   ti = tokens.find("realm");
00046   if (ti != tokens.end()) {
00047     _realm = (*ti).second;
00048   }
00049 
00050   URLSpec canon = get_canonical_url(url);
00051 
00052   ti = tokens.find("domain");
00053   if (ti != tokens.end() && !is_proxy) {
00054     // Now the domain consists of a series of space-separated URL
00055     // prefixes.
00056     const string &domain = (*ti).second;
00057     size_t p = 0;
00058     while (p < domain.length()) {
00059       while (p < domain.length() && isspace(domain[p])) {
00060         ++p;
00061       }
00062       size_t q = p;
00063       while (q < domain.length() && !isspace(domain[q])) {
00064         ++q;
00065       }
00066       if (q > p) {
00067         string domain_str = domain.substr(p, q - p);
00068         URLSpec domain_url(domain_str);
00069         if (domain_url.has_server()) {
00070           // A fully-qualified URL.
00071           _domain.push_back(get_canonical_url(domain_url).get_url());
00072         } else {
00073           // A relative URL; relative to this path.
00074           domain_url = canon;
00075           domain_url.set_path(domain_str);
00076           _domain.push_back(domain_url.get_url());
00077         }
00078       }
00079       p = q;
00080     }
00081 
00082   } else {
00083     // If no domain is defined by the server, use the supplied URL.
00084     // Truncate it to the rightmost slash.
00085     string canon_str = canon.get_url();
00086     size_t slash = canon_str.rfind('/');
00087     nassertv(slash != string::npos);
00088     _domain.push_back(canon_str.substr(0, slash + 1));
00089   }
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: HTTPAuthorization::Destructor
00094 //       Access: Public, Virtual
00095 //  Description: 
00096 ////////////////////////////////////////////////////////////////////
00097 HTTPAuthorization::
00098 ~HTTPAuthorization() {
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: HTTPAuthorization::is_valid
00103 //       Access: Public, Virtual
00104 //  Description: Returns true if the authorization challenge was
00105 //               correctly parsed and is usable, or false if there was
00106 //               some unsupported algorithm or some such requested by
00107 //               the server, rendering the challenge unmeetable.
00108 ////////////////////////////////////////////////////////////////////
00109 bool HTTPAuthorization::
00110 is_valid() {
00111   return true;
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: HTTPAuthorization::parse_authentication_schemes
00116 //       Access: Public, Static
00117 //  Description: Decodes the text following a WWW-Authenticate: or
00118 //               Proxy-Authenticate: header field.
00119 ////////////////////////////////////////////////////////////////////
00120 void HTTPAuthorization::
00121 parse_authentication_schemes(HTTPAuthorization::AuthenticationSchemes &schemes,
00122                              const string &field_value) {
00123   // This string will consist of one or more records of the form:
00124   //
00125   //  scheme token=value[,token=value[,...]]
00126   //
00127   // If there are multiple records, they will be comma-delimited,
00128   // which makes parsing just a bit tricky.
00129 
00130   // Start by skipping initial whitespace.
00131   size_t p = 0;
00132   while (p < field_value.length() && isspace(field_value[p])) {
00133     ++p;
00134   }
00135 
00136   if (p < field_value.length()) {
00137     size_t q = p;
00138     while (q < field_value.length() && !isspace(field_value[q])) {
00139       ++q;
00140     }
00141     // Here's our first scheme.
00142     string scheme = HTTPChannel::downcase(field_value.substr(p, q - p));
00143     Tokens *tokens = &(schemes[scheme]);
00144     
00145     // Now pull off the tokens, one at a time.
00146     p = q + 1;
00147     while (p < field_value.length()) {
00148       q = p;
00149       while (q < field_value.length() && field_value[q] != '=' && 
00150              field_value[q] != ',' && !isspace(field_value[q])) {
00151         ++q;
00152       }
00153       if (field_value[q] == '=') {
00154         // This is a token.
00155         string token = HTTPChannel::downcase(field_value.substr(p, q - p));
00156         string value;
00157         p = scan_quoted_or_unquoted_string(value, field_value, q + 1);
00158         (*tokens)[token] = value;
00159 
00160         // Skip trailing whitespace and extra commas.
00161         while (p < field_value.length() && 
00162                (field_value[p] == ',' || isspace(field_value[p]))) {
00163           ++p;
00164         }
00165 
00166       } else {
00167         // This is not a token; it must be the start of a new scheme.
00168         scheme = HTTPChannel::downcase(field_value.substr(p, q - p));
00169         tokens = &(schemes[scheme]);
00170         p = q + 1;
00171       }
00172     }
00173   }
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: HTTPAuthorization::get_canonical_url
00178 //       Access: Public, Static
00179 //  Description: Returns the "canonical" URL corresponding to this
00180 //               URL.  This is the same URL with an explicit port
00181 //               indication, an explicit scheme, and a non-empty path,
00182 //               etc.
00183 ////////////////////////////////////////////////////////////////////
00184 URLSpec HTTPAuthorization::
00185 get_canonical_url(const URLSpec &url) {
00186   URLSpec canon = url;
00187   canon.set_scheme(canon.get_scheme());
00188   canon.set_username(string());
00189   canon.set_port(canon.get_port());
00190   canon.set_path(canon.get_path());
00191 
00192   return canon;
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: HTTPAuthorization::base64_encode
00197 //       Access: Public, Static
00198 //  Description: Returns the input string encoded using base64.  No
00199 //               respect is paid to maintaining a 76-char line length.
00200 ////////////////////////////////////////////////////////////////////
00201 string HTTPAuthorization::
00202 base64_encode(const string &s) {
00203   // Collect the string 3 bytes at a time into 24-bit words, then
00204   // output each word using 4 bytes.
00205   size_t num_words = (s.size() + 2) / 3;
00206   string result;
00207   result.reserve(num_words * 4);
00208   size_t p;
00209   for (p = 0; p + 2 < s.size(); p += 3) {
00210     unsigned int word = 
00211       ((unsigned)s[p] << 16) |
00212       ((unsigned)s[p + 1] << 8) |
00213       ((unsigned)s[p + 2]);
00214     result += base64_table[(word >> 18) & 0x3f];
00215     result += base64_table[(word >> 12) & 0x3f];
00216     result += base64_table[(word >> 6) & 0x3f];
00217     result += base64_table[(word) & 0x3f];
00218   }
00219   // What's left over?
00220   if (p < s.size()) {
00221     unsigned int word = ((unsigned)s[p] << 16);
00222     p++;
00223     if (p < s.size()) {
00224       word |= ((unsigned)s[p] << 8);
00225       p++;
00226       nassertr(p == s.size(), result);
00227 
00228       result += base64_table[(word >> 18) & 0x3f];
00229       result += base64_table[(word >> 12) & 0x3f];
00230       result += base64_table[(word >> 6) & 0x3f];
00231       result += '=';
00232     } else {
00233       result += base64_table[(word >> 18) & 0x3f];
00234       result += base64_table[(word >> 12) & 0x3f];
00235       result += '=';
00236       result += '=';
00237     }
00238   }
00239 
00240   return result;
00241 }
00242 
00243 ////////////////////////////////////////////////////////////////////
00244 //     Function: HTTPAuthorization::scan_quoted_or_unquoted_string
00245 //       Access: Protected, Static
00246 //  Description: Scans the string source beginning at character
00247 //               position start, to identify either the
00248 //               (space-delimited) unquoted string there, or the
00249 //               (quote-delimited) quoted string.  In either case,
00250 //               fills the string found into result, and returns the
00251 //               next character position after the string (or after
00252 //               its closing quote mark).
00253 ////////////////////////////////////////////////////////////////////
00254 size_t HTTPAuthorization::
00255 scan_quoted_or_unquoted_string(string &result, const string &source, 
00256                                size_t start) {
00257   result = string();
00258 
00259   if (start < source.length()) {
00260     if (source[start] == '"') {
00261       // Quoted string.
00262       size_t p = start + 1;
00263       while (p < source.length() && source[p] != '"') {
00264         if (source[p] == '\\') {
00265           // Backslash escapes.
00266           ++p;
00267           if (p < source.length()) {
00268             result += source[p];
00269             ++p;
00270           }
00271         } else {
00272           result += source[p];
00273           ++p;
00274         }
00275       }
00276       if (p < source.length()) {
00277         ++p;
00278       }
00279       return p;
00280     }
00281 
00282     // Unquoted string.
00283     size_t p = start;
00284     while (p < source.length() && source[p] != ',' && !isspace(source[p])) {
00285       result += source[p];
00286       ++p;
00287     }
00288 
00289     return p;
00290   }
00291 
00292   // Empty string.
00293   return start;
00294 }
00295 
00296 #endif  // HAVE_SSL

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