1 #ifndef CGI___SESSION__HPP
2 #define CGI___SESSION__HPP
3 
4 /*  $Id: cgi_session.hpp 497034 2016-04-04 12:46:26Z dicuccio $
5 * ===========================================================================
6 *
7 *                            PUBLIC DOMAIN NOTICE
8 *               National Center for Biotechnology Information
9 *
10 *  This software/database is a "United States Government Work" under the
11 *  terms of the United States Copyright Act.  It was written as part of
12 *  the author's official duties as a United States Government employee and
13 *  thus cannot be copyrighted.  This software/database is freely available
14 *  to the public for use. The National Library of Medicine and the U.S.
15 *  Government have not placed any restriction on its use or reproduction.
16 *
17 *  Although all reasonable efforts have been taken to ensure the accuracy
18 *  and reliability of the software and data, the NLM and the U.S.
19 *  Government do not and cannot warrant the performance or results that
20 *  may be obtained by using this software or data. The NLM and the U.S.
21 *  Government disclaim all warranties, express or implied, including
22 *  warranties of performance, merchantability or fitness for any particular
23 *  purpose.
24 *
25 *  Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author:  Maxim Didenko
30 *
31 */
32 
33 /// @file cgi_session.hpp
34 /// API to store CGI session data between Web requests.
35 
36 #include <corelib/ncbistd.hpp>
37 
38 #include <memory>
39 
40 /** @addtogroup CGI
41  *
42  * @{
43  */
44 
45 
46 BEGIN_NCBI_SCOPE
47 
48 // fwd-decl
49 class ICgiSessionStorage;
50 class CCgiRequest;
51 class CCgiCookie;
52 
53 /////////////////////////////////////////////////////////////////////////////
54 ///
55 /// CCgiSession --
56 ///
57 ///   Facilitate the transfer of session ID between Web requests.
58 ///   Store and retrieve the CGI session data from an external
59 ///   data storage using the session ID.
60 ///
61 class NCBI_XCGI_EXPORT CCgiSession
62 {
63 public:
64     typedef list<string> TNames;
65 
66     static const char* kDefaultSessionIdName;
67     static const char* kDefaultSessionCookieDomain;
68     static const char* kDefaultSessionCookiePath;
69 
70     /// Session status
71     enum EStatus {
72         eNew,        ///< The session has just been created
73         eLoaded,     ///< The session is loaded
74         eNotLoaded,  ///< The session has not been loaded yet
75         eDeleted,    ///< The session is deleted
76         eImplNotSet  ///< The CGI application didn't set the session
77                      ///< implementation
78     };
79 
80     /// Specifies if a client session cookie can be used to transfer
81     /// session id between requests
82     enum ECookieSupport {
83         eUseCookie,  ///< A session cookie will     be added to the response
84         eNoCookie    ///< A session cookie will not be added to the response
85     };
86 
87     CCgiSession(const CCgiRequest&  request,
88                 ICgiSessionStorage* impl,
89                 EOwnership          impl_ownership = eTakeOwnership,
90                 ECookieSupport      cookie_support = eUseCookie);
91 
92     ~CCgiSession();
93 
94     /// Get session ID.
95     /// @throw CCgiSessionException if session ID is not set and it
96     ///        can not be retrieved from CGI request too.
97     const string& GetId(void) const;
98 
99     /// Set session ID.
100     /// The previously loaded session (if any) will be closed.
101     void SetId(const string& session_id);
102 
103     /// Modify session ID.
104     /// The session must be loaded before calling this method.
105     void ModifyId(const string& new_session_id);
106 
107     /// Load the session.
108     /// @throw CCgiSessionException if session ID is not set and it
109     ///        can not be retrieved from CGI request too.
110     void Load(void);
111 
112     /// Create new session.
113     /// The previously loaded session (if any) will be closed.
114     void CreateNewSession(void);
115 
116     /// Retrieve names of all attributes attached to this session.
117     /// @throw CCgiSessionException if the session is not loaded.
118     TNames GetAttributeNames(void) const;
119 
120     /// Get input stream to read an attribute's data from.
121     /// @param[in] name
122     ///  Name of the attribute
123     /// @param[out] size
124     ///  Size of the attribute's data
125     /// @return
126     ///  Stream to read attribute's data from.If the attribute does not exist,
127     ///  then return an empty stream.
128     /// @throw CCgiSessionException if the session is not loaded.
129     CNcbiIstream& GetAttrIStream(const string& name, size_t* size = NULL);
130 
131     /// Get output stream to write an attribute's data to.
132     /// If the attribute does not exist it will be created and added
133     /// to the session. If the attribute exists its content will be
134     /// overwritten.
135     /// @param[in] name
136     ///  Name of the attribute
137     /// @throw CCgiSessionException if the session is not loaded.
138     CNcbiOstream& GetAttrOStream(const string& name);
139 
140     /// Set attribute data as a string.
141     /// @param[in] name
142     ///  Name of the attribute to set
143     /// @param[in] value
144     ///  Value to set the attribute data to
145     /// @throw CCgiSessionException if the session is not loaded.
146     void SetAttribute(const string& name, const string& value);
147 
148     /// Get attribute data as string.
149     /// @param[in] name
150     ///  Name of the attribute to retrieve
151     /// @return
152     ///  Data of the attribute, if set.
153     /// @throw CCgiSessionException with error code eNotLoaded
154     ///  if the session has not been loaded yet;
155     ///  CCgiSessionException with error code eAttrNotFound if
156     ///  attribute with the specified name was not found;
157     ///  CCgiSessionException with error code eImplException if
158     ///  an error occured during attribute retrieval -- in the
159     ///  latter case, more information can be obtained from the
160     ///  embedded exception.
161     string GetAttribute(const string& name) const;
162 
163     /// Remove attribute from the session.
164     /// @param[in] name
165     ///  Name of the attribute to remove
166     /// @throw CCgiSessionException if the session is not loaded.
167     void RemoveAttribute(const string& name);
168 
169     /// Delete current session
170     /// @throw CCgiSessionException if the session is not loaded.
171     void DeleteSession(void);
172 
173     /// Get current status of the session.
174     EStatus GetStatus(void) const;
175 
176     /// Check if this session object is valid.
177     /// @return True, if this session has been successfully loaded
178     ///         or has just been created. False - if this session
179     ///         does not exist and cannot be used.
180     bool Exists(void) const;
181 
182     /// Get name for session ID.
183     /// @sa SetSessionIdName
184     const string& GetSessionIdName(void) const;
185 
186     /// Set name for session ID.
187     /// This name is used as a cookie name for a session cookie.
188     void SetSessionIdName(const string& name);
189 
190     /// Set session cookie domain
191     /// @sa SetSessionIdName
192     void SetSessionCookieDomain(const string& domain);
193 
194     /// Set session cookie path
195     /// @sa SetSessionIdName
196     void SetSessionCookiePath(const string& path);
197 
198     /// Set session cookie expiration time
199     void SetSessionCookieExpTime(const CTime& exp_time);
200 
201     /// Get a cookie pertaining to the session. May create new cookie,
202     /// if needed and allowed to.
203     /// @return
204     ///  Session CGI cookie;
205     ///  NULL if no session is loaded or if cookie support is disabled.
206     const CCgiCookie* GetSessionCookie(void) const;
207 
208     /// Retrieve a session id from a query string or a session cookie
209     string RetrieveSessionId() const;
210 
211 private:
212     const CCgiRequest& m_Request;
213     ICgiSessionStorage* m_Impl;
214     unique_ptr<ICgiSessionStorage> m_ImplGuard;
215     ECookieSupport m_CookieSupport;
216 
217     string m_SessionId;
218 
219     string m_SessionIdName;
220     string m_SessionCookieDomain;
221     string m_SessionCookiePath;
222     CTime m_SessionCookieExpTime;
223     unique_ptr<CCgiCookie> m_SessionCookie;
224     EStatus m_Status;
225 
226     void x_Load() const;
227 private:
228     CCgiSession(const CCgiSession&);
229     CCgiSession& operator=(const CCgiSession&);
230 };
231 
Exists(void) const232 inline bool CCgiSession::Exists(void) const
233 {
234     return m_Status == eLoaded || m_Status == eNew;
235 }
236 
237 
238 /////////////////////////////////////////////////////////////////////////////
239 ///
240 /// ICgiSessionStorage --
241 ///
242 ///   Implement data storage and retrieval for CCgiSession.
243 ///   @sa CCgiSession
244 ///
245 
246 
247 class NCBI_XCGI_EXPORT ICgiSessionStorage
248 {
249 public:
250     typedef CCgiSession::TNames TNames;
251 
252     virtual ~ICgiSessionStorage();
253 
254     /// Create a new empty session.
255     /// @return ID of the new session
256     virtual string CreateNewSession() = 0;
257 
258     /// Modify session id.
259     /// Change Id of the current session.
260     /// The implementations must handle binary data correctly (e.g.
261     /// NULL characters in the string).
262     virtual void ModifySessionId(const string& new_id) = 0;
263 
264     /// Load the session
265     /// The implementations must handle binary data correctly (e.g.
266     /// NULL characters in the string).
267     /// @param[in]
268     ///  ID of the session
269     /// @return true if the session was loaded, false otherwise
270     virtual bool LoadSession(const string& sessionid) = 0;
271 
272     /// Retrieve names of all attributes attached to this session.
273     virtual TNames GetAttributeNames(void) const = 0;
274 
275     /// Get input stream to read an attribute's data from.
276     /// @param[in] name
277     ///  Name of the attribute
278     /// @param[out] size
279     ///  Size of the attribute's data
280     /// @return
281     ///  Stream to read attribute's data from.If the attribute does not exist,
282     ///  then return an empty stream.
283     virtual CNcbiIstream& GetAttrIStream(const string& name,
284                                          size_t* size = 0) = 0;
285 
286     /// Get output stream to write an attribute's data to.
287     /// If the attribute does not exist it will be created and added
288     /// to the session. If the attribute exists its content will be
289     /// overwritten.
290     /// @param[in] name
291     ///  Name of the attribute
292     virtual CNcbiOstream& GetAttrOStream(const string& name) = 0;
293 
294     /// Set attribute data as a string.
295     /// @param[in] name
296     ///  Name of the attribute to set
297     /// @param[in] value
298     ///  Value to set the attribute data to
299     virtual void SetAttribute(const string& name, const string& value) = 0;
300 
301     /// Get attribute data as string.
302     /// @param[in] name
303     ///  Name of the attribute to retrieve
304     /// @return
305     ///  Data of the attribute, if set.
306     /// @throw CCgiSessionException with error code eNotLoaded
307     ///  if the session has not been loaded yet;
308     ///  CCgiSessionException with error code eAttrNotFound if
309     ///  attribute with the specified name was not found;
310     ///  CCgiSessionException with error code eImplException if
311     ///  an error occured during attribute retrieval -- in the
312     ///  latter case, more information can be obtained from the
313     ///  embedded exception.
314     virtual string GetAttribute(const string& name) const = 0;
315 
316     /// Remove attribute from the session.
317     /// @param[in] name
318     ///  Name of the attribute to remove
319     virtual void RemoveAttribute(const string& name) = 0;
320 
321     /// Delete current session
322     virtual void DeleteSession() = 0;
323 
324     /// Reset the session. The an implementation should close
325     /// all input/ouptut streams here.
326     virtual void Reset() = 0;
327 };
328 
329 /////////////////////////////////////////////////////////////////////
330 
331 inline
GetStatus() const332 CCgiSession::EStatus CCgiSession::GetStatus() const
333 {
334     return m_Status;
335 }
336 inline
GetSessionIdName() const337 const string& CCgiSession::GetSessionIdName() const
338 {
339     return m_SessionIdName;
340 }
341 inline
SetSessionIdName(const string & name)342 void CCgiSession::SetSessionIdName(const string& name)
343 {
344     m_SessionIdName = name;
345 }
346 inline
SetSessionCookieDomain(const string & domain)347 void CCgiSession::SetSessionCookieDomain(const string& domain)
348 {
349     m_SessionCookieDomain = domain;
350 }
351 inline
SetSessionCookiePath(const string & path)352 void CCgiSession::SetSessionCookiePath(const string& path)
353 {
354     m_SessionCookiePath = path;
355 }
356 inline
SetSessionCookieExpTime(const CTime & exp_time)357 void CCgiSession::SetSessionCookieExpTime(const CTime& exp_time)
358 {
359     m_SessionCookieExpTime = exp_time;
360 }
361 
362 
363 END_NCBI_SCOPE
364 
365 
366 /* @} */
367 
368 #endif  /* CGI___SESSION__HPP */
369