1 /*  $Id: nst_protocol_utils.cpp 493945 2016-03-02 17:13:12Z satskyse $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors:  Sergey Satskiy
27  *
28  * File Description: NetStorage communication protocol utils
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/request_ctx.hpp>
34 #include <connect/ncbi_socket.hpp>
35 #include <connect/services/netservice_api_expt.hpp>
36 
37 #include "nst_protocol_utils.hpp"
38 #include "nst_exception.hpp"
39 #include "error_codes.hpp"
40 
41 
42 
43 BEGIN_NCBI_SCOPE
44 
45 
SetSessionAndIPAndPHID(const CJsonNode & message,const CSocket & peer)46 void SetSessionAndIPAndPHID(const CJsonNode &  message,
47                             const CSocket &    peer)
48 {
49     if (message.HasKey("SessionID")) {
50         string  session = message.GetString("SessionID");
51         if (!session.empty())
52             CDiagContext::GetRequestContext().SetSessionID(
53                     session);
54     }
55 
56 
57     string      client_ip;
58     if (message.HasKey("ClientIP"))
59         client_ip = message.GetString("ClientIP");
60 
61     if (client_ip.empty())
62         CDiagContext::GetRequestContext().SetClientIP(
63                                 peer.GetPeerAddress(eSAF_IP));
64     else
65         CDiagContext::GetRequestContext().SetClientIP(
66                                 client_ip);
67 
68     // CXX-7893: ncbi_context has preference over ncbi_phid
69     bool        ncbi_context_deserialized = false;
70     if (message.HasKey("ncbi_context")) {
71         try {
72             string      context = message.GetString("ncbi_context");
73             CRequestContext_PassThrough().Deserialize(context,
74                             CRequestContext_PassThrough::eFormat_UrlEncoded);
75 
76             ncbi_context_deserialized = true;
77         } catch (const exception &  ex) {
78             ERR_POST(ex.what());
79         }
80     }
81 
82     if (ncbi_context_deserialized == false && message.HasKey("ncbi_phid")) {
83         try {
84             string      ncbi_phid = message.GetString("ncbi_phid");
85             if (!ncbi_phid.empty())
86                 CDiagContext::GetRequestContext().SetHitID(ncbi_phid);
87         } catch (const exception &  ex) {
88             ERR_POST(ex.what());
89         }
90     }
91 }
92 
93 
94 SCommonRequestArguments
ExtractCommonFields(const CJsonNode & message)95 ExtractCommonFields(const CJsonNode &  message)
96 {
97     SCommonRequestArguments     result;
98     try {
99         result.m_SerialNumber = message.GetInteger("SN");
100         result.m_MessageType = message.GetString("Type");
101     }
102     catch (const std::exception & ex) {
103         // Converting to the CNetStorageServerException is done to
104         // have generic request status handling.
105         NCBI_THROW(CNetStorageServerException, eInvalidIncomingMessage,
106                    ex.what());
107     }
108     return result;
109 }
110 
111 
112 TNetStorageFlags
ExtractStorageFlags(const CJsonNode & message)113 ExtractStorageFlags(const CJsonNode &  message)
114 {
115     TNetStorageFlags    result = 0;
116 
117     if (message.HasKey("StorageFlags")) {
118         CJsonNode   flags = message.GetByKey("StorageFlags");
119         if (flags.HasKey("Fast") && flags.GetBoolean("Fast"))
120             result |= fNST_Fast;
121         if (flags.HasKey("Persistent") && flags.GetBoolean("Persistent"))
122             result |= fNST_Persistent;
123         if (flags.HasKey("NetCache") && flags.GetBoolean("NetCache"))
124             result |= fNST_NetCache;
125         if (flags.HasKey("FileTrack") && flags.GetBoolean("FileTrack"))
126             result |= fNST_FileTrack;
127         if (flags.HasKey("Movable") && flags.GetBoolean("Movable"))
128             result |= fNST_Movable;
129         if (flags.HasKey("Cacheable") && flags.GetBoolean("Cacheable"))
130             result |= fNST_Cacheable;
131         if (flags.HasKey("NoMetaData") && flags.GetBoolean("NoMetaData"))
132             result |= fNST_NoMetaData;
133     }
134     return result;
135 }
136 
137 
138 SICacheSettings
ExtractICacheSettings(const CJsonNode & message)139 ExtractICacheSettings(const CJsonNode &  message)
140 {
141     SICacheSettings     result;
142 
143     if (message.HasKey("ICache")) {
144         CJsonNode   settings = message.GetByKey("ICache");
145         if (settings.HasKey("ServiceName"))
146             result.m_ServiceName = settings.GetString("ServiceName");
147         if (settings.HasKey("CacheName"))
148             result.m_CacheName = settings.GetString("CacheName");
149     }
150     return result;
151 }
152 
153 
154 SUserKey
ExtractUserKey(const CJsonNode & message)155 ExtractUserKey(const CJsonNode &  message)
156 {
157     SUserKey        result;
158 
159     if (message.HasKey("UserKey")) {
160         CJsonNode   user_key = message.GetByKey("UserKey");
161         if (user_key.HasKey("UniqueID"))
162             result.m_UniqueID = user_key.GetString("UniqueID");
163         if (user_key.HasKey("AppDomain"))
164             result.m_AppDomain = user_key.GetString("AppDomain");
165     }
166     return result;
167 }
168 
169 
170 CJsonNode
CreateResponseMessage(Int8 serial_number)171 CreateResponseMessage(Int8  serial_number)
172 {
173     CJsonNode       reply_message(CJsonNode::NewObjectNode());
174 
175     reply_message.SetString("Type", kMessageTypeReply);
176     reply_message.SetString("Status", kStatusOK);
177     reply_message.SetInteger("RE", serial_number);
178 
179     return reply_message;
180 }
181 
182 
183 CJsonNode
CreateErrorResponseMessage(Int8 serial_number,Int8 error_code,const string & error_message,const string & scope,Int8 sub_code)184 CreateErrorResponseMessage(Int8            serial_number,
185                            Int8            error_code,
186                            const string &  error_message,
187                            const string &  scope,
188                            Int8            sub_code)
189 {
190     CJsonNode       reply_message(CJsonNode::NewObjectNode());
191     CJsonNode       errors(CJsonNode::NewArrayNode());
192 
193     reply_message.SetString("Type", kMessageTypeReply);
194     reply_message.SetString("Status", kStatusError);
195     reply_message.SetInteger("RE", serial_number);
196 
197     errors.Append(CreateIssue(error_code, error_message, scope, sub_code));
198 
199     reply_message.SetByKey("Errors", errors);
200 
201     return reply_message;
202 }
203 
204 
205 void
AppendWarning(CJsonNode & message,Int8 code,const string & warning_message,const string & scope,Int8 sub_code)206 AppendWarning(CJsonNode &     message,
207               Int8            code,
208               const string &  warning_message,
209               const string &  scope,
210               Int8            sub_code)
211 {
212     CJsonNode   warnings;
213     if (!message.HasKey("Warnings"))
214         message.SetByKey("Warnings", warnings = CJsonNode::NewArrayNode());
215     else
216         warnings = message.GetByKey("Warnings");
217 
218     warnings.Append(CreateIssue(code, warning_message, scope, sub_code));
219 }
220 
221 
222 void
AppendError(CJsonNode & message,Int8 code,const string & error_message,const string & scope,Int8 sub_code,bool update_status)223 AppendError(CJsonNode &     message,
224             Int8            code,
225             const string &  error_message,
226             const string &  scope,
227             Int8            sub_code,
228             bool            update_status)
229 {
230     if (update_status)
231         message.SetString("Status", kStatusError);
232 
233     CJsonNode   errors;
234     if (!message.HasKey("Errors"))
235         message.SetByKey("Errors", errors = CJsonNode::NewArrayNode());
236     else
237         errors = message.GetByKey("Errors");
238 
239     errors.Append(CreateIssue(code, error_message, scope, sub_code));
240 }
241 
242 
243 CJsonNode
CreateIssue(Int8 error_code,const string & error_message,const string & scope,Int8 sub_code)244 CreateIssue(Int8  error_code,
245             const string &  error_message,
246             const string &  scope,
247             Int8  sub_code)
248 {
249     CJsonNode       issue_node(CJsonNode::NewObjectNode());
250 
251     issue_node.SetInteger("Code", error_code);
252     issue_node.SetString("Message", error_message);
253     issue_node.SetString("Scope", scope);
254     issue_node.SetInteger("SubCode", sub_code);
255 
256     return issue_node;
257 }
258 
259 
GetReplyMessageProperties(const exception & ex,string * error_scope,Int8 * error_code,unsigned int * error_sub_code)260 bool GetReplyMessageProperties(const exception &  ex,
261                                string *           error_scope,
262                                Int8 *             error_code,
263                                unsigned int *     error_sub_code)
264 {
265     const CNetStorageException *    p =
266                 dynamic_cast<const CNetStorageException *>(&ex);
267     if (p != NULL) {
268         *error_scope = p->GetType();
269         *error_code = NCBI_ERRCODE_X_NAME(NetStorageException_ErrorCode);
270         *error_sub_code = p->GetErrCode();
271         return true;
272     }
273 
274     const CNetServiceException *    p1 =
275                 dynamic_cast<const CNetServiceException *>(&ex);
276     if (p1 != NULL) {
277         *error_scope = p1->GetType();
278         *error_code = NCBI_ERRCODE_X_NAME(NetServiceException_ErrorCode);
279         *error_sub_code = p1->GetErrCode();
280         return true;
281     }
282 
283     const CNetStorageServerException *  p2 =
284                 dynamic_cast<const CNetStorageServerException *>(&ex);
285     if (p2 != NULL) {
286         *error_scope = p2->GetType();
287         *error_code = NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode);
288         *error_sub_code = p2->GetErrCode();
289         return true;
290     }
291 
292     const CException *  p3 =
293                 dynamic_cast<const CException *>(&ex);
294     if (p3 != NULL) {
295         *error_scope = p3->GetType();
296         *error_code = NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode);
297         *error_sub_code = 0;
298         return false;
299     }
300 
301     *error_scope = kScopeStdException;
302     *error_code = NCBI_ERRCODE_X_NAME(NetStorageServer_ErrorCode);
303     *error_sub_code = 0;
304     return false;
305 }
306 
307 
308 END_NCBI_SCOPE
309 
310