1 #ifndef NCBI_CGI_CTX__HPP
2 #define NCBI_CGI_CTX__HPP
3 
4 /*  $Id: cgictx.hpp 540924 2017-07-12 15:06:18Z grichenk $
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:
30 *	Vsevolod Sandomirskiy
31 *
32 * File Description:
33 *   Basic CGI Application class
34 */
35 
36 #include <cgi/cgiapp.hpp>
37 #include <cgi/cgi_session.hpp>
38 #include <connect/ncbi_types.h>
39 #include <cgi/cgi_exception.hpp>
40 
41 
42 /** @addtogroup CGIBase
43  *
44  * @{
45  */
46 
47 
48 BEGIN_NCBI_SCOPE
49 
50 class CUrl;
51 
52 /////////////////////////////////////////////////////////////////////////////
53 //
54 //  CCgiServerContext::
55 //
56 
57 class NCBI_XCGI_EXPORT CCgiServerContext
58 {
59 public:
60     virtual ~CCgiServerContext(void);
61 };
62 
63 
64 
65 /////////////////////////////////////////////////////////////////////////////
66 //
67 //  CCtxMsg::
68 //
69 
70 class NCBI_XCGI_EXPORT CCtxMsg
71 {
72 public:
73     virtual ~CCtxMsg(void);
74     virtual CNcbiOstream& Write(CNcbiOstream& os) const = 0;
75 };
76 
77 
78 /* @} */
79 
80 
81 inline
operator <<(CNcbiOstream & os,const CCtxMsg & ctx_msg)82 CNcbiOstream& operator<< (CNcbiOstream& os, const CCtxMsg& ctx_msg)
83 {
84     return ctx_msg.Write(os);
85 }
86 
87 
88 /** @addtogroup CGIBase
89  *
90  * @{
91  */
92 
93 
94 /////////////////////////////////////////////////////////////////////////////
95 //
96 //  CCtxMsgString::
97 //
98 
99 class NCBI_XCGI_EXPORT CCtxMsgString : public CCtxMsg
100 {
101 public:
CCtxMsgString(const string & msg)102     CCtxMsgString(const string& msg) : m_Message(msg) {}
103     virtual ~CCtxMsgString(void);
104     virtual CNcbiOstream& Write(CNcbiOstream& os) const;
105 
106     static const char* sm_nl;
107 
108 private:
109     string m_Message;
110 };
111 
112 
113 /////////////////////////////////////////////////////////////////////////////
114 //
115 //  CCgiContext::
116 //
117 // CCgiContext is a wrapper for request, response, server context.
118 // In addition, it contains list of messages (as HTML nodes).
119 // Having non-const reference, CCgiContext's user has access to all its
120 // internal data.
121 // Context will try to create request from given data or default request
122 // on any request creation error
123 //
124 
125 class CNcbiEnvironment;
126 class CNcbiRegistry;
127 class CNcbiResource;
128 class CCgiApplication;
129 
130 
131 class NCBI_XCGI_EXPORT CCgiContext
132 {
133 public:
134     CCgiContext(CCgiApplication&        app,
135                 const CNcbiArguments*   args = 0 /* D: app.GetArguments()   */,
136                 const CNcbiEnvironment* env  = 0 /* D: app.GetEnvironment() */,
137                 CNcbiIstream*           inp  = 0 /* see ::CCgiRequest(istr) */,
138                 CNcbiOstream*           out  = 0 /* see ::CCgiResponse(out) */,
139                 int                     ifd  = -1,
140                 int                     ofd  = -1,
141                 size_t                  errbuf_size = 256, /* see CCgiRequest */
142                 CCgiRequest::TFlags     flags = 0
143                 );
144 
145     CCgiContext(CCgiApplication&        app,
146                 CNcbiIstream*           inp /* see ::CCgiRequest(istr) */,
147                 CNcbiOstream*           out /* see ::CCgiResponse(out) */,
148                 CCgiRequest::TFlags     flags = 0
149                 );
150 
151     CCgiContext(ICgiSessionStorage*     session_storage,
152                 const CNcbiArguments*   args = 0 /* D: app.GetArguments()   */,
153                 const CNcbiEnvironment* env  = 0 /* D: app.GetEnvironment() */,
154                 CNcbiIstream*           inp  = 0 /* see ::CCgiRequest(istr) */,
155                 CNcbiOstream*           out  = 0 /* see ::CCgiResponse(out) */,
156                 int                     ifd  = -1,
157                 int                     ofd  = -1,
158                 size_t                  errbuf_size = 256, /* see CCgiRequest */
159                 CCgiRequest::TFlags     flags = 0
160                 );
161 
162     virtual ~CCgiContext(void);
163 
164     const CCgiApplication& GetApp(void) const;
165 
166     const CNcbiRegistry& GetConfig(void) const;
167     CNcbiRegistry& GetConfig(void);
168 
169     // these methods will throw exception if no server context is set
170     const CNcbiResource& GetResource(void) const;
171     CNcbiResource&       GetResource(void);
172 
173     const CCgiRequest& GetRequest(void) const;
174     CCgiRequest&       GetRequest(void);
175 
176     const CCgiResponse& GetResponse(void) const;
177     CCgiResponse&       GetResponse(void);
178 
179     // these methods will throw exception if no server context set
180     const CCgiServerContext& GetServCtx(void) const;
181     CCgiServerContext&       GetServCtx(void);
182 
183     // message buffer functions
184     CNcbiOstream& PrintMsg(CNcbiOstream& os);
185 
186     void PutMsg(const string& msg);
187     void PutMsg(CCtxMsg*      msg);
188 
189     bool EmptyMsg(void);
190     void ClearMsg(void);
191 
192     // request access wrappers
193 
194     // return entry from request
195     // return empty string if no such entry
196     // throw runtime_error if there are several entries with the same name
197     const CCgiEntry& GetRequestValue(const string& name, bool* is_found = 0)
198         const;
199 
200     void AddRequestValue    (const string& name, const CCgiEntry& value);
201     void RemoveRequestValues(const string& name);
202     void ReplaceRequestValue(const string& name, const CCgiEntry& value);
203 
204     /// Whether to use the port number when composing the CGI's own URL
205     /// @sa GetSelfURL()
206     /// @deprecated The flag is ignored, use GetSelfURL(void).
207     enum ESelfUrlPort {
208         eSelfUrlPort_Use,     ///< Use port number in self-URL
209         eSelfUrlPort_Strip,   ///< Do not use port number in self-URL
210         eSelfUrlPort_Default  ///< Use port number, except for NCBI front-ends
211     };
212 
213     /// Using HTTP environment variables, compose the CGI's own URL as:
214     ///   SCHEME://SERVER_NAME[:SERVER_PORT]/SCRIPT_NAME
215     /// @deprecated The flag is ignored, use GetSelfURL(void).
216     NCBI_DEPRECATED
GetSelfURL(ESelfUrlPort) const217     const string& GetSelfURL(ESelfUrlPort /*use_port*/) const
218         { return GetSelfURL(); }
219 
220     /// Using HTTP environment variables, compose the CGI's own URL as:
221     ///   SCHEME://SERVER_NAME[:SERVER_PORT]/SCRIPT_NAME
222     /// Port is always included if it does not correspond to the scheme's
223     /// default port.
224     const string& GetSelfURL(void) const;
225 
226     /// Check if the current scheme is secure (https) or not (http).
227     bool IsSecure(void) const;
228 
229     // Which streams are ready?
230     enum EStreamStatus {
231         fInputReady  = 0x1,
232         fOutputReady = 0x2
233     };
234     typedef int TStreamStatus;  // binary OR of 'EStreamStatus'
235     TStreamStatus GetStreamStatus(STimeout* timeout) const;
236     TStreamStatus GetStreamStatus(void) const; // supplies {0,0}
237 
238     string RetrieveTrackingId() const;
239 
240     /// Check if the context has any pending errors, perform any required actions
241     /// (e.g. throw an exception).
242     void CheckStatus(void) const;
243 
244     /// Process cross-origin resource sharing (CORS) request.
245     /// If the request is a preflight one, send back the required data
246     /// and return true (in this case normal ProcessRequest should not
247     /// be called). Otherwise check if CORS is enabled and add the
248     /// required headers to the response.
249     static bool ProcessCORSRequest(const CCgiRequest& request,
250                                    CCgiResponse&      response);
251 
252 private:
253     CCgiApplication& x_GetApp(void) const;
254     CCgiServerContext& x_GetServerContext(void) const;
255     void x_InitSession(CCgiRequest::TFlags flags,
256                        ICgiSessionStorage* session_storage = nullptr);
257 
258     void x_SetStatus(CCgiException::EStatusCode code, const string& msg) const;
259 
260     // Secure protocol flag.
261     enum ESecureMode {
262         eSecure_NotSet,
263         eSecure_Off,
264         eSecure_On
265     };
266 
267     CCgiApplication*        m_App;
268     unique_ptr<CCgiRequest> m_Request;  // CGI request  information
269     CCgiResponse            m_Response; // CGI response information
270     unique_ptr<CCgiSession> m_Session;  // CGI session
271 
272     // message buffer
273     typedef list< AutoPtr<CCtxMsg> > TMessages;
274     TMessages m_Messages;
275 
276     // server context will be obtained from CCgiApp::LoadServerContext()
277     unique_ptr<CCgiServerContext> m_ServerContext; // application defined context
278 
279     mutable string m_SelfURL;
280     mutable string m_TrackingId; // cached tracking id
281     mutable ESecureMode m_SecureMode;
282 
283     // Request status code and message. The status is non-zero if there
284     // is an error to report.
285     mutable CCgiException::EStatusCode m_StatusCode;
286     mutable string m_StatusMessage;
287 
288     // forbidden
289     CCgiContext(const CCgiContext&);
290     CCgiContext& operator=(const CCgiContext&);
291 };
292 
293 
294 /////////////////////////////////////////////////////////////////////////////
295 //
296 //  CCgiSessionParameters:
297 //  This class is used to pass additional optional parameters from a CGI
298 //  application to CGI session
299 
300 class CCgiSessionParameters
301 {
302 public:
303 
304     /// Spescify which class is responsible for Session Storage destruction
305     /// if set to eTakeOwnership, then a CGI session will delete it, otherwise
306     /// the CGI application should do it.
307     /// Default the CGI session takes responsibility.
SetImplOwnership(EOwnership owner)308     void SetImplOwnership(EOwnership owner) { m_ImplOwner = owner; }
309 
310     /// Do not use a cookie to transfer session id between requests
311     /// By default cookie is enabled
DisableCookie()312     void DisableCookie() { m_CookieEnabled = false; }
313 
314     /// Set name of the cookie with session id.
315     /// Default: ncbi_sessionid
SetSessionIdName(const string & name)316     void SetSessionIdName(const string& name) { m_SessionIdName = name; }
317 
318     /// Set session cookie's domain
319     /// Default: .ncbi.nlm.nih.gov
SetSessionCookieDomain(const string & domain)320     void SetSessionCookieDomain(const string& domain)
321     { m_SessionCookieDomain = domain; }
322 
323     /// Set session cookie's path
324     /// Default: /
SetSessionCookiePath(const string & path)325     void SetSessionCookiePath(const string& path)
326     { m_SessionCookiePath = path; }
327 
328     /// Set session cookie's expiration time
329     /// Default: none
SetSessionCookieExpTime(const CTime & exp_time)330     void SetSessionCookieExpTime(const CTime& exp_time)
331     { m_SessionCookieExpTime = exp_time; }
332 
333 private:
334 
335     // Only CgiContext can create an instance of this class
336     friend class CCgiContext;
CCgiSessionParameters()337     CCgiSessionParameters() :
338         m_ImplOwner(eTakeOwnership), m_CookieEnabled(true),
339         m_SessionIdName(CCgiSession::kDefaultSessionIdName),
340         m_SessionCookieDomain(CCgiSession::kDefaultSessionCookieDomain),
341         m_SessionCookiePath(CCgiSession::kDefaultSessionCookiePath) {}
342 
343     EOwnership m_ImplOwner;
344     bool m_CookieEnabled;
345     string m_SessionIdName;
346     string m_SessionCookieDomain;
347     string m_SessionCookiePath;
348     CTime m_SessionCookieExpTime;
349 };
350 
351 /* @} */
352 
353 
354 /////////////////////////////////////////////////////////////////////////////
355 
356 /////////////////////////////////////////////////////////////////////////////
357 //  IMPLEMENTATION of INLINE functions
358 /////////////////////////////////////////////////////////////////////////////
359 
360 
361 
362 /////////////////////////////////////////////////////////////////////////////
363 //  CCgiContext::
364 //
365 
366 inline
GetApp(void) const367 const CCgiApplication& CCgiContext::GetApp(void) const
368 {
369     return x_GetApp();
370 }
371 
372 
373 inline
GetRequest(void) const374 const CCgiRequest& CCgiContext::GetRequest(void) const
375 {
376     return *m_Request;
377 }
378 
379 
380 inline
GetRequest(void)381 CCgiRequest& CCgiContext::GetRequest(void)
382 {
383     return *m_Request;
384 }
385 
386 
387 inline
GetResponse(void) const388 const CCgiResponse& CCgiContext::GetResponse(void) const
389 {
390     return m_Response;
391 }
392 
393 
394 inline
GetResponse(void)395 CCgiResponse& CCgiContext::GetResponse(void)
396 {
397     return m_Response;
398 }
399 
400 
401 inline
GetServCtx(void) const402 const CCgiServerContext& CCgiContext::GetServCtx(void) const
403 {
404     return x_GetServerContext();
405 }
406 
407 
408 inline
GetServCtx(void)409 CCgiServerContext& CCgiContext::GetServCtx(void)
410 {
411     return x_GetServerContext();
412 }
413 
414 
415 inline
PrintMsg(CNcbiOstream & os)416 CNcbiOstream& CCgiContext::PrintMsg(CNcbiOstream& os)
417 {
418     ITERATE (TMessages, it, m_Messages) {
419         os << **it;
420     }
421     return os;
422 }
423 
424 
425 inline
PutMsg(const string & msg)426 void CCgiContext::PutMsg(const string& msg)
427 {
428     m_Messages.push_back(new CCtxMsgString(msg));
429 }
430 
431 
432 inline
PutMsg(CCtxMsg * msg)433 void CCgiContext::PutMsg(CCtxMsg* msg)
434 {
435     m_Messages.push_back(msg);
436 }
437 
438 
439 inline
EmptyMsg(void)440 bool CCgiContext::EmptyMsg(void)
441 {
442     return m_Messages.empty();
443 }
444 
445 
446 inline
ClearMsg(void)447 void CCgiContext::ClearMsg(void)
448 {
449     m_Messages.clear();
450 }
451 
452 
453 inline
GetStreamStatus(void) const454 CCgiContext::TStreamStatus CCgiContext::GetStreamStatus(void) const
455 {
456     STimeout timeout = {0, 0};
457     return GetStreamStatus(&timeout);
458 }
459 
460 
461 END_NCBI_SCOPE
462 
463 #endif // NCBI_CGI_CTX__HPP
464