1 #ifndef CGI___CGI_SERIAL__HPP
2 #define CGI___CGI_SERIAL__HPP
3 
4 /*  $Id: cgi_serial.hpp 535133 2017-05-05 14:01:02Z ivanov $
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 cont_serial.hpp
34 
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbistre.hpp>
37 #include <corelib/ncbistr.hpp>
38 #include <cgi/ncbicgi.hpp>
39 
40 #include <vector>
41 
42 BEGIN_NCBI_SCOPE
43 
44 ///////////////////////////////////////////////////////
45 ///
46 /// template<typename TElem> CContElemConverter
47 ///
48 /// The helper class for storing/retrieving a call to/from a string
49 ///
50 template<typename TElem>
51 class CContElemConverter
52 {
53 public:
FromString(const string & str)54     static TElem  FromString(const string& str)   { return TElem(str);   }
ToString(const TElem & elem)55     static string ToString  (const TElem&  elem)  { return string(elem); }
56 };
57 
58 
59 ///////////////////////////////////////////////////////
60 ///
61 /// template<> CContElemConverter<string>
62 ///
63 /// The specialization of CContElemConverter for the string class.
64 ///
65 template<>
66 class CContElemConverter<string>
67 {
68 public:
FromString(const string & str)69     static const string& FromString(const string& str)  { return str; }
ToString(const string & str)70     static const string& ToString  (const string& str)  { return str; }
71 };
72 
73 ///////////////////////////////////////////////////////
74 ///
75 /// template<> CContElemConverter<CCgiEntry>
76 ///
77 /// The specialization of CContElemConverter for the CCgiEntry class.
78 ///
79 template<>
80 class NCBI_XCGI_EXPORT CContElemConverter<CCgiEntry>
81 {
82 public:
83     static CCgiEntry  FromString(const string& str);
84     static string ToString  (const CCgiEntry&  elem);
85 };
86 
87 
88 ///////////////////////////////////////////////////////
89 ///
90 /// COStreamHelper
91 ///
92 /// The helper class for storing a data into to a stream
93 /// in the form
94 /// data_size data
95 ///
96 class COStreamHelper
97 {
98 public:
COStreamHelper(CNcbiOstream & os)99     COStreamHelper(CNcbiOstream& os) : m_Ostream(os), m_str(nullptr) {}
~COStreamHelper()100     ~COStreamHelper() {  try { flush(); } catch (...) {}   }
101 
operator CNcbiOstream&()102     operator CNcbiOstream&() { return x_GetStrm(); }
103 
104     template<typename T>
operator <<(const T & t)105     COStreamHelper& operator<<(const T& t)
106     {
107         x_GetStrm() << t;
108         return *this;
109     }
110 
flush(bool write_empty_data=false)111     void flush(bool write_empty_data = false)
112     {
113         if (m_str.get() != NULL) {
114             unique_ptr<CNcbiOstrstream> strm(m_str.release());
115             string s = CNcbiOstrstreamToString(*strm);
116             // Historically counted, but did not output, a final \0.
117             m_Ostream << (s.size() + 1) << ' ' << s;
118         } else if (write_empty_data)
119             m_Ostream << 1 << ' ';
120     }
121 
122 private:
x_GetStrm()123     CNcbiOstream& x_GetStrm() {
124         if (m_str.get() == NULL) {
125             m_str.reset(new CNcbiOstrstream);
126         }
127         return *m_str;
128     }
129     CNcbiOstream& m_Ostream;
130     unique_ptr<CNcbiOstrstream> m_str;
131 };
132 
133 
134 ///////////////////////////////////////////////////////
135 ///
136 /// Read a string from a stream. The string is following
137 /// by its size
138 ///
ReadStringFromStream(CNcbiIstream & is)139 inline string ReadStringFromStream(CNcbiIstream& is)
140 {
141     string str;
142     if (!is.good() || is.eof())
143         return str;
144 
145     size_t size;
146     is >> size;
147     if (!is.good() || is.eof())
148         return str;
149     if (size > 0) {
150         AutoPtr<char, ArrayDeleter<char> > buf(new char[size]);
151         is.read(buf.get(), size);
152         size_t count = (size_t)is.gcount();
153         if (count > 0)
154             str.append(buf.get()+1, count-1);
155     }
156     return str;
157 }
158 
159 ///////////////////////////////////////////////////////
160 ///
161 /// Write a map to a stream
162 ///
163 template<typename TMap>
WriteMap(CNcbiOstream & os,const TMap & cont)164 CNcbiOstream& WriteMap(CNcbiOstream& os, const TMap& cont)
165 {
166     typedef CContElemConverter<typename TMap::key_type>    TKeyConverter;
167     typedef CContElemConverter<typename TMap::mapped_type> TValueConverter;
168 
169     COStreamHelper ostr(os);
170     ITERATE(typename TMap, it, cont) {
171         if (it != cont.begin())
172             ostr << '&';
173         ostr << NStr::URLEncode(TKeyConverter::ToString(it->first)) << '='
174              << NStr::URLEncode(TValueConverter::ToString(it->second));
175     }
176     ostr.flush(true);
177     return os;
178 }
179 
180 
181 ///////////////////////////////////////////////////////
182 ///
183 /// Read a map from a stream
184 ///
185 template<typename TMap>
ReadMap(CNcbiIstream & is,TMap & cont)186 CNcbiIstream& ReadMap(CNcbiIstream& is, TMap& cont)
187 {
188     typedef CContElemConverter<typename TMap::key_type>    TKeyConverter;
189     typedef CContElemConverter<typename TMap::mapped_type> TValueConverter;
190 
191     string input = ReadStringFromStream(is);
192 
193     vector<CTempString> pairs;
194     NStr::Split(input, "&", pairs,
195                 NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
196 
197     cont.clear();
198     ITERATE(vector<CTempString>, it, pairs) {
199         CTempString key;
200         CTempString value;
201         NStr::SplitInTwo(*it, "=", key, value);
202         cont.insert(typename TMap::value_type(
203                     TKeyConverter::FromString(NStr::URLDecode(key)),
204                     TValueConverter::FromString(NStr::URLDecode(value)))
205                    );
206     }
207 
208     return is;
209 }
210 
211 ///////////////////////////////////////////////////////
212 ///
213 /// Write a container to a stream
214 ///
215 template<typename TCont>
WriteContainer(CNcbiOstream & os,const TCont & cont)216 CNcbiOstream& WriteContainer(CNcbiOstream& os, const TCont& cont)
217 {
218     typedef CContElemConverter<typename TCont::value_type> TValueConverter;
219     COStreamHelper ostr(os);
220     ITERATE(typename TCont, it, cont) {
221         if (it != cont.begin())
222             ostr << '&';
223         ostr << NStr::URLEncode(TValueConverter::ToString(*it));
224     }
225     ostr.flush(true);
226     return os;
227 }
228 
229 ///////////////////////////////////////////////////////
230 ///
231 /// Read a container from a stream
232 ///
233 template<typename TCont>
ReadContainer(CNcbiIstream & is,TCont & cont)234 CNcbiIstream& ReadContainer(CNcbiIstream& is, TCont& cont)
235 {
236     typedef CContElemConverter<typename TCont::value_type> TValueConverter;
237 
238     string input = ReadStringFromStream(is);
239 
240     vector<CTempString> strings;
241     NStr::Split(input, "&", strings,
242                 NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
243 
244     cont.clear();
245     ITERATE(vector<CTempString>, it, strings) {
246         cont.push_back(TValueConverter::FromString(NStr::URLDecode(*it)));
247     }
248 
249     return is;
250 }
251 
252 
253 ///////////////////////////////////////////////////////
254 ///
255 /// Write cgi cookeis to a stream
256 ///
257 NCBI_XCGI_EXPORT
258 extern CNcbiOstream&
259 WriteCgiCookies(CNcbiOstream& os, const CCgiCookies& cont);
260 
261 ///////////////////////////////////////////////////////
262 ///
263 /// Read cgi cookeis from a stream
264 ///
265 NCBI_XCGI_EXPORT
266 extern CNcbiIstream&
267 ReadCgiCookies(CNcbiIstream& is, CCgiCookies& cont);
268 
269 ///////////////////////////////////////////////////////
270 ///
271 /// Write an environment to a stream
272 ///
273 NCBI_XCGI_EXPORT
274 extern CNcbiOstream&
275 WriteEnvironment(CNcbiOstream& os, const CNcbiEnvironment& cont);
276 
277 ///////////////////////////////////////////////////////
278 ///
279 /// Write an environment from a stream
280 ///
281 NCBI_XCGI_EXPORT
282 extern CNcbiIstream&
283 ReadEnvironment(CNcbiIstream& is, CNcbiEnvironment& cont);
284 
285 END_NCBI_SCOPE
286 
287 #endif  /* CGI___CGI_SERIAL__HPP */
288