First commit
[anna.git] / source / http / wims20 / ServerSide.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <stdlib.h>
38
39 #include <anna/core/tracing/Logger.hpp>
40
41 #include <anna/http/Request.hpp>
42
43 #include <anna/http/wims20/ServerSide.hpp>
44
45 using namespace std;
46 using namespace anna;
47
48 /*
49  * (1) Si estamos esperando http://xxx/zzzz hay que verificar que no vamos a dar por buena una
50  * expresión con la forma: http://xxx/zzzzAAAAAA, p.e.
51  */
52 void http::wims20::ServerSide::decode(const http::Request& request)
53 throw(RuntimeException) {
54   Abstract::clear();
55   const string& uri = request.getURI();
56   // Calcula la parte corta que hemos definido para el servicio
57   const string& shortFixedPart = Abstract::calculeShortFixedPart();
58   const int fixedLen = shortFixedPart.length();
59   bool isOk = true;
60
61   if(uri.compare(0, fixedLen, shortFixedPart) != 0)
62     isOk = false;
63   else if(uri [fixedLen] != '/')                                                  // (1)
64     isOk = false;
65
66   if(isOk == false) {
67     string msg("http::wims20::ServerSide::decode | URI: ");
68     msg += uri;
69     msg += " | URI does not match with service '";
70     msg += shortFixedPart;
71     msg += "'" ;
72     throw RuntimeException(msg, ANNA_FILE_LOCATION);
73   }
74
75   // http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters
76   // Quita toda la parte "http://domain-openapis/path-openapis"
77   string hierarchyAndParameter = uri.substr(fixedLen + 1);
78   // Separa la jerarguía de los parámetros (si los hay).
79   const Tokenizer& tthp = split(SplitCode::HierarchyAndParameter, hierarchyAndParameter);
80   const int size = tthp.size();
81
82   if(size == 0 || size > 2) {
83     string msg("URI '");
84     msg += uri;
85     msg += "' is not valid";
86     throw RuntimeException(msg, ANNA_FILE_LOCATION);
87   }
88
89   try {
90     switch(size) {
91     case 1:
92       decodeHierarchy(tthp [0]);
93       break;
94     case 2:
95       decodeHierarchy(tthp [0]);
96       decodeParameters(tthp [1]);
97       break;
98     }
99   } catch(RuntimeException& ex) {
100     string msg("URI '");
101     msg += uri;
102     msg += "' is not valid | ";
103     msg += ex.getText();
104     throw RuntimeException(msg, ex.getFromFile(), ex.getFromLine());
105   }
106
107   LOGDEBUG(
108     string msg("http::wims20::ServerSide::decode | URI: ");
109     msg += uri;
110     msg += " | Result: ";
111     msg += asString();
112     Logger::debug(msg, ANNA_FILE_LOCATION);
113   );
114 }
115
116 const string* http::wims20::ServerSide::getValue(const char* name, const Exception::Mode::_v mode) const
117 throw(RuntimeException) {
118   const string* result = NULL;
119
120   if(hasParameters() == true) {
121     for(const_parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) {
122       if(parameter_name(ii) == name) {
123         const string& value = parameter_value(ii);
124         result = &value;
125         break;
126       }
127     }
128   }
129
130   if(result == NULL && (mode == Exception::Mode::Throw || mode == Exception::Mode::Trace)) {
131     string msg(asString());
132     msg += " | Parameter '";
133     msg += name;
134     msg += "' not found";
135     RuntimeException ex(msg, ANNA_FILE_LOCATION);
136
137     if(mode == Exception::Mode::Throw)
138       throw ex;
139
140     ex.trace();
141   }
142
143   return result;
144 }
145
146 const char* http::wims20::ServerSide::getCStringValue(const char* name, const Exception::Mode::_v mode) const
147 throw(RuntimeException) {
148   const string* temp = getValue(name, mode);
149   return (temp == NULL) ? NULL : temp->c_str();
150 }
151
152 int http::wims20::ServerSide::getIntegerValue(const char* name, const Exception::Mode::_v mode) const
153 throw(RuntimeException) {
154   const string* tmp = getValue(name, mode);
155
156   if(tmp == NULL)
157     return 0;
158
159   const char* value = tmp->c_str();
160   return (anna_strncmp(value, "0x", 2) == 0) ? strtol(value + 2, NULL, 16) :  atoi(value);
161 }
162
163 /* Nos ha debido llegar algo así como: serviceID/guid/*{other_possible_levels}
164  */
165 void http::wims20::ServerSide::decodeHierarchy(const std::string& hierarchy)
166 throw(RuntimeException) {
167   const Tokenizer& items = split(SplitCode::HierarchyItem, hierarchy);
168   Abstract::setServiceID(items [0]);
169   Abstract::setGUID(items [1]);
170
171   if(items.size() > 2) {
172     Tokenizer::const_iterator maxii, ii = items.begin();
173     ii ++;
174     ii ++;
175
176     for(maxii = items.end(); ii != maxii; ii ++)
177       Abstract::other_level_add(Tokenizer::data(ii));
178   }
179 }
180
181 /* Nos ha debido llegar algo así como: name=value&*{nameN=valueN}
182  */
183 void http::wims20::ServerSide::decodeParameters(const std::string& parameters)
184 throw(RuntimeException) {
185   const Tokenizer& tkparams = split(SplitCode::Parameters, parameters);
186
187   for(Tokenizer::const_iterator ii = tkparams.begin(), maxii = tkparams.end(); ii != maxii; ii ++) {
188     const string& parameter = Tokenizer::data(ii);
189     // Separa los XXX=YYYY
190     const Tokenizer& tkparam = split(SplitCode::ParameterAndArgument, parameter);
191     Abstract::parameter_set(tkparam [0], tkparam [1]);
192   }
193 }
194
195 const Tokenizer& http::wims20::ServerSide::split(const SplitCode::_v splitZone, const std::string& str)
196 throw(RuntimeException) {
197   static const char* separator [] = { "?", "/", "&", "=", NULL };
198   a_tokenizer [splitZone].apply(str, separator [splitZone]);
199   LOGDEBUG(
200     string msg("String: ");
201     msg += str;
202     msg += " | Separator: ";
203     msg += separator [splitZone];
204     Logger::debug(msg, ANNA_FILE_LOCATION);
205   );
206   return a_tokenizer [splitZone];
207 }
208