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