Panda3D
 All Classes Functions Variables Enumerations
httpCookie.cxx
00001 // Filename: httpCookie.cxx
00002 // Created by:  drose (26Aug04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "httpCookie.h"
00016 
00017 #ifdef HAVE_OPENSSL
00018 
00019 #include "ctype.h"
00020 #include "httpChannel.h"
00021 
00022 ////////////////////////////////////////////////////////////////////
00023 //     Function: HTTPCookie::operator <
00024 //       Access: Published
00025 //  Description: The sorting operator allows the cookies to be stored
00026 //               in a single dictionary; it returns nonequal only if
00027 //               the cookies are different in name, path, or domain.
00028 ////////////////////////////////////////////////////////////////////
00029 bool HTTPCookie::
00030 operator < (const HTTPCookie &other) const {
00031   if (_domain != other._domain) {
00032     return _domain < other._domain;
00033   }
00034 
00035   if (_path != other._path) {
00036     // We use reverse sorting on the path, so that cookies with longer
00037     // paths will be sent to the server before cookies with shorter
00038     // paths.
00039     return _path > other._path;
00040   }
00041 
00042   if (_name != other._name) {
00043     return _name < other._name;
00044   }
00045 
00046   return false;
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: HTTPCookie::update_from
00051 //       Access: Published
00052 //  Description: Assuming the operator < method, above, has already
00053 //               evaluated these two cookies as equal, then assign the
00054 //               remaining values (value, expiration date, secure
00055 //               flag) from the indicated cookie.  This is guaranteed
00056 //               not to change the ordering of the cookie in a set,
00057 //               and so can be used to update an existing cookie
00058 //               within a set with new values.
00059 ////////////////////////////////////////////////////////////////////
00060 void HTTPCookie::
00061 update_from(const HTTPCookie &other) {
00062   nassertv(!(other < *this) && !(*this < other));
00063 
00064   _value = other._value;
00065   _expires = other._expires;
00066   _secure = other._secure;
00067 }
00068 
00069 ////////////////////////////////////////////////////////////////////
00070 //     Function: HTTPCookie::parse_set_cookie
00071 //       Access: Published
00072 //  Description: Separates out the parameter/value pairs of the
00073 //               Set-Cookie header and assigns the values of the
00074 //               cookie appropriate.  Returns true if the header is
00075 //               parsed correctly, false if something is not
00076 //               understood.
00077 ////////////////////////////////////////////////////////////////////
00078 bool HTTPCookie::
00079 parse_set_cookie(const string &format, const URLSpec &url) {
00080   _name = string();
00081   _value = string();
00082   _domain = url.get_server();
00083   _path = url.get_path();
00084   _expires = HTTPDate();
00085   _secure = false;
00086 
00087   bool okflag = true;
00088   bool first_param = true;
00089   
00090   size_t start = 0;
00091   while (start < format.length() && isspace(format[start])) {
00092     start++;
00093   }
00094   size_t semicolon = format.find(';', start);
00095 
00096   while (semicolon != string::npos) {
00097     if (!parse_cookie_param(format.substr(start, semicolon - start), 
00098                             first_param)) {
00099       okflag = false;
00100     }
00101     first_param = false;
00102     start = semicolon + 1;
00103     while (start < format.length() && isspace(format[start])) {
00104       start++;
00105     }
00106     semicolon = format.find(';', start);
00107   }
00108 
00109   if (!parse_cookie_param(format.substr(start), first_param)) {
00110     okflag = false;
00111   }
00112 
00113   return okflag;
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: HTTPCookie::matches_url
00118 //       Access: Published
00119 //  Description: Returns true if the cookie is appropriate to send
00120 //               with the indicated URL request, false otherwise.
00121 ////////////////////////////////////////////////////////////////////
00122 bool HTTPCookie::
00123 matches_url(const URLSpec &url) const {
00124   if (_domain.empty()) {
00125     return false;
00126   }
00127   string server = url.get_server();
00128   if (server == _domain || 
00129       (string(".") + server) == _domain ||
00130       (server.length() > _domain.length() &&
00131        server.substr(server.length() - _domain.length()) == _domain &&
00132        (_domain[0] == '.' || server[server.length() - _domain.length() - 1] == '.'))) {
00133     // The domain matches.
00134 
00135     string path = url.get_path();
00136     if (path.length() >= _path.length() &&
00137         path.substr(0, _path.length()) == _path) {
00138 
00139       // The path matches too.
00140       if (_secure && !url.is_ssl()) {
00141         // Oops, can't send a secure cookie over a non-secure connection.
00142         return false;
00143       }
00144 
00145       return true;
00146     }
00147   }
00148 
00149   return false;
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: HTTPCookie::output
00154 //       Access: Published
00155 //  Description: 
00156 ////////////////////////////////////////////////////////////////////
00157 void HTTPCookie::
00158 output(ostream &out) const {
00159   out << _name << "=" << _value
00160       << "; path=" << _path << "; domain=" << _domain;
00161 
00162   if (has_expires()) {
00163     out << "; expires=" << _expires;
00164   }
00165   
00166   if (_secure) {
00167     out << "; secure";
00168   }
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: HTTPCookie::parse_cookie_param
00173 //       Access: Private
00174 //  Description: Called internally by parse_set_cookie() with each
00175 //               parameter=value pair split out from the header
00176 //               string.  first_param will be true for the first
00177 //               parameter (which has special meaning).  This should
00178 //               return true on success, false on failure.
00179 ////////////////////////////////////////////////////////////////////
00180 bool HTTPCookie::
00181 parse_cookie_param(const string &param, bool first_param) {
00182   size_t equals = param.find('=');
00183 
00184   string key, value;
00185   if (equals == string::npos) {
00186     key = param;
00187   } else {
00188     key = param.substr(0, equals);
00189     value = param.substr(equals + 1);
00190   }
00191 
00192   if (first_param) {
00193     _name = key;
00194     _value = value;
00195 
00196   } else {
00197     key = HTTPChannel::downcase(key);
00198     if (key == "expires") {
00199       _expires = HTTPDate(value);
00200       if (!_expires.is_valid()) {
00201         return false;
00202       }
00203 
00204     } else if (key == "path") {
00205       _path = value;
00206 
00207     } else if (key == "domain") {
00208       _domain = HTTPChannel::downcase(value);
00209 
00210       // From RFC 2965: If an explicitly specified value does not
00211       // start with a dot, the user agent supplies a leading dot.
00212       if (!_domain.empty() && _domain[0] != '.') {
00213         _domain = string(".") + _domain;
00214       }
00215 
00216     } else if (key == "secure") {
00217       _secure = true;
00218 
00219     } else {
00220       return false;
00221     }
00222   }
00223 
00224   return true;
00225 }
00226 
00227 #endif  // HAVE_OPENSSL
 All Classes Functions Variables Enumerations