From 12c443e6fb23c2b300e2587f4430d3384ddc585c Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 27 Aug 2004 17:25:35 +0000 Subject: [PATCH] add cookie support --- panda/src/downloader/Sources.pp | 9 +- .../src/downloader/downloader_composite2.cxx | 1 + panda/src/downloader/httpChannel.cxx | 22 +- panda/src/downloader/httpClient.cxx | 134 ++++++++++ panda/src/downloader/httpClient.h | 16 +- panda/src/downloader/httpCookie.I | 232 ++++++++++++++++++ panda/src/downloader/httpCookie.cxx | 221 +++++++++++++++++ panda/src/downloader/httpCookie.h | 93 +++++++ 8 files changed, 722 insertions(+), 6 deletions(-) create mode 100644 panda/src/downloader/httpCookie.I create mode 100644 panda/src/downloader/httpCookie.cxx create mode 100644 panda/src/downloader/httpCookie.h diff --git a/panda/src/downloader/Sources.pp b/panda/src/downloader/Sources.pp index 427f28a741..32ce28ac3d 100644 --- a/panda/src/downloader/Sources.pp +++ b/panda/src/downloader/Sources.pp @@ -22,8 +22,9 @@ extractor.h \ httpAuthorization.I httpAuthorization.h \ httpBasicAuthorization.I httpBasicAuthorization.h \ - httpClient.I httpClient.h \ httpChannel.I httpChannel.h \ + httpClient.I httpClient.h \ + httpCookie.I httpCookie.h \ httpDate.I httpDate.h \ httpDigestAuthorization.I httpDigestAuthorization.h \ httpEntityTag.I httpEntityTag.h \ @@ -50,8 +51,9 @@ extractor.cxx \ httpAuthorization.cxx \ httpBasicAuthorization.cxx \ - httpClient.cxx \ httpChannel.cxx \ + httpClient.cxx \ + httpCookie.cxx \ httpDate.cxx \ httpDigestAuthorization.cxx \ httpEntityTag.cxx \ @@ -76,8 +78,9 @@ extractor.h \ httpAuthorization.I httpAuthorization.h \ httpBasicAuthorization.I httpBasicAuthorization.h \ - httpClient.I httpClient.h \ httpChannel.I httpChannel.h \ + httpClient.I httpClient.h \ + httpCookie.I httpCookie.h \ httpDate.I httpDate.h \ httpDigestAuthorization.I httpDigestAuthorization.h \ httpEntityTag.I httpEntityTag.h \ diff --git a/panda/src/downloader/downloader_composite2.cxx b/panda/src/downloader/downloader_composite2.cxx index 31bca44bbb..f02cb56782 100644 --- a/panda/src/downloader/downloader_composite2.cxx +++ b/panda/src/downloader/downloader_composite2.cxx @@ -2,6 +2,7 @@ #include "httpBasicAuthorization.cxx" #include "httpChannel.cxx" #include "httpClient.cxx" +#include "httpCookie.cxx" #include "httpDate.cxx" #include "httpDigestAuthorization.cxx" #include "httpEntityTag.cxx" diff --git a/panda/src/downloader/httpChannel.cxx b/panda/src/downloader/httpChannel.cxx index 124f64e836..ff57ef701e 100644 --- a/panda/src/downloader/httpChannel.cxx +++ b/panda/src/downloader/httpChannel.cxx @@ -18,6 +18,7 @@ #include "httpChannel.h" #include "httpClient.h" +#include "httpCookie.h" #include "bioStream.h" #include "ssl_utils.h" #include "chunkedStream.h" @@ -791,7 +792,11 @@ reached_done_state() { << "Unable to download body.\n"; } return false; + } else { + if (_state != S_reading_body) { + _body_stream = NULL; + } _started_download = true; _last_run_time = ClockObject::get_global_clock()->get_real_time(); return true; @@ -1831,7 +1836,12 @@ run_begin_body() { reset_to_new(); } else { - nassertr(_body_stream == NULL, false); + // We shouldn't already be in the middle of reading some other + // body when we come here. + nassertd(_body_stream == NULL) { + reset_to_new(); + return false; + } _body_stream = read_body(); if (_body_stream == (ISocketStream *)NULL) { if (downloader_cat.is_debug()) { @@ -1841,7 +1851,9 @@ run_begin_body() { reset_to_new(); } else { - _state = S_reading_body; + if (_state != S_reading_body) { + _body_stream = NULL; + } } } @@ -3115,6 +3127,8 @@ make_header() { break; } + _client->send_cookies(stream, _request.get_url()); + if (!_body.empty()) { stream << "Content-Type: application/x-www-form-urlencoded\r\n" @@ -3220,6 +3234,10 @@ store_header_field(const string &field_name, const string &field_value) { (*hi).second += ", "; (*hi).second += field_value; } + + if (field_name == "set-cookie") { + _client->set_cookie(HTTPCookie(field_value, _request.get_url())); + } } #ifndef NDEBUG diff --git a/panda/src/downloader/httpClient.cxx b/panda/src/downloader/httpClient.cxx index 2a262ecbe0..15d4114a0f 100644 --- a/panda/src/downloader/httpClient.cxx +++ b/panda/src/downloader/httpClient.cxx @@ -609,6 +609,140 @@ get_username(const string &server, const string &realm) const { return string(); } +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::set_cookie +// Access: Published +// Description: Stores the indicated cookie in the client's list of +// cookies, as if it had been received from a server. +//////////////////////////////////////////////////////////////////// +void HTTPClient:: +set_cookie(const HTTPCookie &cookie) { + if (cookie.is_expired()) { + clear_cookie(cookie); + + } else { + pair result = _cookies.insert(cookie); + if (!result.second) { + // We already had a cookie matching the supplied domain/path/name, + // so replace it. + const HTTPCookie &orig_cookie = *result.first; + ((HTTPCookie &)orig_cookie).update_from(cookie); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::clear_cookie +// Access: Published +// Description: Removes the cookie with the matching domain/path/name +// from the client's list of cookies. Returns true if +// it was removed, false if the cookie was not matched. +//////////////////////////////////////////////////////////////////// +bool HTTPClient:: +clear_cookie(const HTTPCookie &cookie) { + Cookies::iterator ci = _cookies.find(cookie); + if (ci != _cookies.end()) { + _cookies.erase(ci); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::clear_all_cookies +// Access: Published +// Description: Removes the all stored cookies from the client. +//////////////////////////////////////////////////////////////////// +void HTTPClient:: +clear_all_cookies() { + _cookies.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::has_cookie +// Access: Published +// Description: Returns true if there is a cookie in the client +// matching the given cookie's domain/path/name, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool HTTPClient:: +has_cookie(const HTTPCookie &cookie) const { + Cookies::const_iterator ci = _cookies.find(cookie); + return (ci != _cookies.end()); +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::get_cookie +// Access: Published +// Description: Looks up and returns the cookie in the client +// matching the given cookie's domain/path/name. If +// there is no matching cookie, returns an empty cookie. +//////////////////////////////////////////////////////////////////// +HTTPCookie HTTPClient:: +get_cookie(const HTTPCookie &cookie) const { + Cookies::const_iterator ci = _cookies.find(cookie); + if (ci != _cookies.end()) { + return (*ci); + } + + return HTTPCookie(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::write_cookies +// Access: Published +// Description: Outputs the complete list of cookies stored on the +// client, for all domains, including the expired +// cookies (which will normally not be sent back to a +// host). +//////////////////////////////////////////////////////////////////// +void HTTPClient:: +write_cookies(ostream &out) const { + Cookies::const_iterator ci; + for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) { + out << *ci << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::send_cookies +// Access: Published +// Description: Writes to the indicated ostream a set of Cookie: +// lines for sending the cookies appropriate to the +// indicated URL along with an HTTP request. This also +// removes expired cookies. +//////////////////////////////////////////////////////////////////// +void HTTPClient:: +send_cookies(ostream &out, const URLSpec &url) { + HTTPDate now = HTTPDate::now(); + bool any_expired = false; + + Cookies::const_iterator ci; + for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) { + const HTTPCookie &cookie = (*ci); + if (cookie.is_expired(now)) { + any_expired = true; + + } else if (cookie.matches_url(url)) { + out << "Cookie: " << cookie.get_name() << "=" + << cookie.get_value() << "\r\n"; + } + } + + if (any_expired) { + Cookies new_cookies; + Cookies::const_iterator ci; + for (ci = _cookies.begin(); ci != _cookies.end(); ++ci) { + const HTTPCookie &cookie = (*ci); + if (!cookie.is_expired(now)) { + new_cookies.insert(new_cookies.end(), cookie); + } + } + _cookies.swap(new_cookies); + } +} + //////////////////////////////////////////////////////////////////// // Function: HTTPClient::load_client_certificate // Access: Published diff --git a/panda/src/downloader/httpClient.h b/panda/src/downloader/httpClient.h index 9835cea980..1ca3e1c8e3 100644 --- a/panda/src/downloader/httpClient.h +++ b/panda/src/downloader/httpClient.h @@ -31,10 +31,12 @@ #include "urlSpec.h" #include "httpAuthorization.h" #include "httpEnum.h" +#include "httpCookie.h" #include "globPattern.h" #include "pointerTo.h" #include "pvector.h" #include "pmap.h" +#include "pset.h" #include @@ -82,6 +84,15 @@ PUBLISHED: void set_username(const string &server, const string &realm, const string &username); string get_username(const string &server, const string &realm) const; + void set_cookie(const HTTPCookie &cookie); + bool clear_cookie(const HTTPCookie &cookie); + void clear_all_cookies(); + bool has_cookie(const HTTPCookie &cookie) const; + HTTPCookie get_cookie(const HTTPCookie &cookie) const; + + void write_cookies(ostream &out) const; + void send_cookies(ostream &out, const URLSpec &url); + INLINE void set_client_certificate_filename(const Filename &filename); INLINE void set_client_certificate_pem(const string &pem); INLINE void set_client_certificate_passphrase(const string &passphrase); @@ -157,7 +168,7 @@ private: typedef pmap Usernames; Usernames _usernames; - typedef map Realms; + typedef pmap Realms; class Domain { public: Realms _realms; @@ -165,6 +176,9 @@ private: typedef pmap Domains; Domains _proxy_domains, _www_domains; + typedef pset Cookies; + Cookies _cookies; + Filename _client_certificate_filename; string _client_certificate_pem; string _client_certificate_passphrase; diff --git a/panda/src/downloader/httpCookie.I b/panda/src/downloader/httpCookie.I new file mode 100644 index 0000000000..cd2af2206a --- /dev/null +++ b/panda/src/downloader/httpCookie.I @@ -0,0 +1,232 @@ +// Filename: httpCookie.I +// Created by: drose (26Aug04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::Constructor +// Access: Published +// Description: Constructs an empty cookie. +//////////////////////////////////////////////////////////////////// +INLINE HTTPCookie:: +HTTPCookie() : + _secure(false) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::Constructor +// Access: Published +// Description: Constructs a cookie according to the indicated +// string, presumably the tag of a Set-Cookie header. +// There is no way to detect a formatting error in the +// string with this constructor. +//////////////////////////////////////////////////////////////////// +INLINE HTTPCookie:: +HTTPCookie(const string &format, const URLSpec &url) { + parse_set_cookie(format, url); +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::Constructor +// Access: Published +// Description: Constructs a cookie with the indicated name, path, +// and domain values, but no other data. This is most +// useful for looking up an existing cookie in the +// HTTPClient. +//////////////////////////////////////////////////////////////////// +INLINE HTTPCookie:: +HTTPCookie(const string &name, const string &path, const string &domain) : + _name(name), + _path(path), + _domain(domain), + _secure(false) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE HTTPCookie:: +~HTTPCookie() { +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::set_name +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +set_name(const string &name) { + _name = name; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::get_name +// Access: Published +// Description: Returns the name of the cookie. This is the key +// value specified by the server. +//////////////////////////////////////////////////////////////////// +INLINE const string &HTTPCookie:: +get_name() const { + return _name; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::set_value +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +set_value(const string &value) { + _value = value; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::get_value +// Access: Published +// Description: Returns the value of the cookie. This is the +// arbitrary string associated with the cookie's name, +// as specified by the server. +//////////////////////////////////////////////////////////////////// +INLINE const string &HTTPCookie:: +get_value() const { + return _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::set_domain +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +set_domain(const string &domain) { + _domain = domain; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::get_domain +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE const string &HTTPCookie:: +get_domain() const { + return _domain; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::set_path +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +set_path(const string &path) { + _path = path; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::get_path +// Access: Published +// Description: Returns the prefix of the URL paths on the server for +// which this cookie will be sent. +//////////////////////////////////////////////////////////////////// +INLINE const string &HTTPCookie:: +get_path() const { + return _path; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::set_expires +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +set_expires(const HTTPDate &expires) { + _expires = expires; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::clear_expires +// Access: Published +// Description: Removes the expiration date on the cookie. +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +clear_expires() { + _expires = HTTPDate(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::has_expires +// Access: Published +// Description: Returns true if the cookie has an expiration date, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool HTTPCookie:: +has_expires() const { + return _expires.is_valid(); +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::get_expires +// Access: Published +// Description: Returns the expiration date of the cookie if it is +// set, or an invalid date if it is not. +//////////////////////////////////////////////////////////////////// +INLINE HTTPDate HTTPCookie:: +get_expires() const { + return _expires; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::set_secure +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void HTTPCookie:: +set_secure(bool secure) { + _secure = secure; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::get_secure +// Access: Published +// Description: Returns true if the server has indicated this is a +// "secure" cookie which should only be sent over an +// HTTPS channel. +//////////////////////////////////////////////////////////////////// +INLINE bool HTTPCookie:: +get_secure() const { + return _secure; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::is_expired +// Access: Published +// Description: Returns true if the cookie's expiration date is +// before the indicated date, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool HTTPCookie:: +is_expired(const HTTPDate &now) const { + return _expires.is_valid() && _expires < now; +} + +INLINE ostream &operator << (ostream &out, const HTTPCookie &cookie) { + cookie.output(out); + return out; +} diff --git a/panda/src/downloader/httpCookie.cxx b/panda/src/downloader/httpCookie.cxx new file mode 100644 index 0000000000..76e95d0006 --- /dev/null +++ b/panda/src/downloader/httpCookie.cxx @@ -0,0 +1,221 @@ +// Filename: httpCookie.cxx +// Created by: drose (26Aug04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "httpCookie.h" + +#ifdef HAVE_SSL + +#include "ctype.h" +#include "httpChannel.h" + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::operator < +// Access: Published +// Description: The sorting operator allows the cookies to be stored +// in a single dictionary; it returns nonequal only if +// the cookies are different in name, path, or domain. +//////////////////////////////////////////////////////////////////// +bool HTTPCookie:: +operator < (const HTTPCookie &other) const { + if (_domain != other._domain) { + return _domain < other._domain; + } + + if (_path != other._path) { + // We use reverse sorting on the path, so that cookies with longer + // paths will be sent to the server before cookies with shorter + // paths. + return _path > other._path; + } + + if (_name != other._name) { + return _name < other._name; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::update_from +// Access: Published +// Description: Assuming the operator < method, above, has already +// evaluated these two cookies as equal, then assign the +// remaining values (value, expiration date, secure +// flag) from the indicated cookie. This is guaranteed +// not to change the ordering of the cookie in a set, +// and so can be used to update an existing cookie +// within a set with new values. +//////////////////////////////////////////////////////////////////// +void HTTPCookie:: +update_from(const HTTPCookie &other) { + nassertv(!(other < *this) && !(*this < other)); + + _value = other._value; + _expires = other._expires; + _secure = other._secure; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::parse_set_cookie +// Access: Published +// Description: Separates out the parameter/value pairs of the +// Set-Cookie header and assigns the values of the +// cookie appropriate. Returns true if the header is +// parsed correctly, false if something is not +// understood. +//////////////////////////////////////////////////////////////////// +bool HTTPCookie:: +parse_set_cookie(const string &format, const URLSpec &url) { + _name = string(); + _value = string(); + _domain = url.get_server(); + _path = url.get_path(); + _expires = HTTPDate(); + _secure = false; + + bool okflag = true; + bool first_param = true; + + size_t start = 0; + while (start < format.length() && isspace(format[start])) { + start++; + } + size_t semicolon = format.find(';', start); + + while (semicolon != string::npos) { + if (!parse_cookie_param(format.substr(start, semicolon - start), + first_param)) { + okflag = false; + } + first_param = false; + start = semicolon + 1; + while (start < format.length() && isspace(format[start])) { + start++; + } + semicolon = format.find(';', start); + } + + if (!parse_cookie_param(format.substr(start), first_param)) { + okflag = false; + } + + return okflag; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::matches_url +// Access: Published +// Description: Returns true if the cookie is appropriate to send +// with the indicated URL request, false otherwise. +//////////////////////////////////////////////////////////////////// +bool HTTPCookie:: +matches_url(const URLSpec &url) const { + string server = url.get_server(); + if (server == _domain || + (server.length() > _domain.length() && + server.substr(server.length() - _domain.length()) == _domain && + server[server.length() - _domain.length() - 1] == '.')) { + // The domain matches. + + string path = url.get_path(); + if (path.length() >= _path.length() && + path.substr(0, _path.length()) == _path) { + + // The path matches too. + if (_secure && !url.is_ssl()) { + // Oops, can't send a secure cookie over a non-secure connection. + return false; + } + + return true; + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::output +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void HTTPCookie:: +output(ostream &out) const { + out << _name << "=" << _value + << "; path=" << _path << "; domain=" << _domain; + + if (has_expires()) { + out << "; expires=" << _expires; + } + + if (_secure) { + out << "; secure"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: HTTPCookie::parse_cookie_param +// Access: Private +// Description: Called internally by parse_set_cookie() with each +// parameter=value pair split out from the header +// string. first_param will be true for the first +// parameter (which has special meaning). This should +// return true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool HTTPCookie:: +parse_cookie_param(const string ¶m, bool first_param) { + size_t equals = param.find('='); + + string key, value; + if (equals == string::npos) { + key = param; + } else { + key = param.substr(0, equals); + value = param.substr(equals + 1); + } + + if (first_param) { + _name = key; + _value = value; + + } else { + key = HTTPChannel::downcase(key); + if (key == "expires") { + _expires = HTTPDate(value); + if (!_expires.is_valid()) { + return false; + } + + } else if (key == "path") { + _path = value; + + } else if (key == "domain") { + _domain = HTTPChannel::downcase(value); + + } else if (key == "secure") { + _secure = true; + + } else { + return false; + } + } + + return true; +} + +#endif // HAVE_SSL diff --git a/panda/src/downloader/httpCookie.h b/panda/src/downloader/httpCookie.h new file mode 100644 index 0000000000..835137a4f8 --- /dev/null +++ b/panda/src/downloader/httpCookie.h @@ -0,0 +1,93 @@ +// Filename: httpCookie.h +// Created by: drose (26Aug04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef HTTPCOOKIE_H +#define HTTPCOOKIE_H + +#include "pandabase.h" + +// This module requires OpenSSL to compile, even if you do not intend +// to use this to establish https connections; this is because it uses +// the OpenSSL library to portably handle all of the socket +// communications. + +#ifdef HAVE_SSL + +#include "httpDate.h" +#include "urlSpec.h" + +//////////////////////////////////////////////////////////////////// +// Class : HTTPCookie +// Description : A cookie sent from an HTTP server to be stored on the +// client and returned when the path and/or domain +// matches. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEXPRESS HTTPCookie { +PUBLISHED: + INLINE HTTPCookie(); + INLINE HTTPCookie(const string &format, const URLSpec &url); + INLINE HTTPCookie(const string &name, const string &path, const string &domain); + INLINE ~HTTPCookie(); + + INLINE void set_name(const string &name); + INLINE const string &get_name() const; + + INLINE void set_value(const string &value); + INLINE const string &get_value() const; + + INLINE void set_domain(const string &domain); + INLINE const string &get_domain() const; + + INLINE void set_path(const string &path); + INLINE const string &get_path() const; + + INLINE void set_expires(const HTTPDate &expires); + INLINE void clear_expires(); + INLINE bool has_expires() const; + INLINE HTTPDate get_expires() const; + + INLINE void set_secure(bool flag); + INLINE bool get_secure() const; + + bool operator < (const HTTPCookie &other) const; + void update_from(const HTTPCookie &other); + + bool parse_set_cookie(const string &format, const URLSpec &url); + INLINE bool is_expired(const HTTPDate &now = HTTPDate::now()) const; + bool matches_url(const URLSpec &url) const; + + void output(ostream &out) const; + +private: + bool parse_cookie_param(const string ¶m, bool first_param); + + string _name; + string _value; + string _domain; + string _path; + HTTPDate _expires; + bool _secure; +}; + +INLINE ostream &operator << (ostream &out, const HTTPCookie &cookie); + +#include "httpCookie.I" + +#endif // HAVE_SSL + +#endif