Fix local server for multiple applications
[anna.git] / wims20 / ServerSide.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <stdlib.h>
10
11 #include <anna/core/tracing/Logger.hpp>
12
13 #include <anna/http/Request.hpp>
14
15 #include <anna/http/wims20/ServerSide.hpp>
16
17 using namespace std;
18 using namespace anna;
19
20 /*
21  * (1) Si estamos esperando http://xxx/zzzz hay que verificar que no vamos a dar por buena una
22  * expresión con la forma: http://xxx/zzzzAAAAAA, p.e.
23  */
24 void http::wims20::ServerSide::decode(const http::Request& request)
25 noexcept(false) {
26   Abstract::clear();
27   const string& uri = request.getURI();
28   // Calcula la parte corta que hemos definido para el servicio
29   const string& shortFixedPart = Abstract::calculeShortFixedPart();
30   const int fixedLen = shortFixedPart.length();
31   bool isOk = true;
32
33   if(uri.compare(0, fixedLen, shortFixedPart) != 0)
34     isOk = false;
35   else if(uri [fixedLen] != '/')                                                  // (1)
36     isOk = false;
37
38   if(isOk == false) {
39     string msg("http::wims20::ServerSide::decode | URI: ");
40     msg += uri;
41     msg += " | URI does not match with service '";
42     msg += shortFixedPart;
43     msg += "'" ;
44     throw RuntimeException(msg, ANNA_FILE_LOCATION);
45   }
46
47   // http://domain-openapis/path-openapis/serviceID/guid/other_possible_levels?query_parameters
48   // Quita toda la parte "http://domain-openapis/path-openapis"
49   string hierarchyAndParameter = uri.substr(fixedLen + 1);
50   // Separa la jerarguía de los parámetros (si los hay).
51   const Tokenizer& tthp = split(SplitCode::HierarchyAndParameter, hierarchyAndParameter);
52   const int size = tthp.size();
53
54   if(size == 0 || size > 2) {
55     string msg("URI '");
56     msg += uri;
57     msg += "' is not valid";
58     throw RuntimeException(msg, ANNA_FILE_LOCATION);
59   }
60
61   try {
62     switch(size) {
63     case 1:
64       decodeHierarchy(tthp [0]);
65       break;
66     case 2:
67       decodeHierarchy(tthp [0]);
68       decodeParameters(tthp [1]);
69       break;
70     }
71   } catch(RuntimeException& ex) {
72     string msg("URI '");
73     msg += uri;
74     msg += "' is not valid | ";
75     msg += ex.getText();
76     throw RuntimeException(msg, ex.getFromFile(), ex.getFromLine());
77   }
78
79   LOGDEBUG(
80     string msg("http::wims20::ServerSide::decode | URI: ");
81     msg += uri;
82     msg += " | Result: ";
83     msg += asString();
84     Logger::debug(msg, ANNA_FILE_LOCATION);
85   );
86 }
87
88 const string* http::wims20::ServerSide::getValue(const char* name, const Exception::Mode::_v mode) const
89 noexcept(false) {
90   const string* result = NULL;
91
92   if(hasParameters() == true) {
93     for(const_parameter_iterator ii = parameter_begin(), maxii = parameter_end(); ii != maxii; ii ++) {
94       if(parameter_name(ii) == name) {
95         const string& value = parameter_value(ii);
96         result = &value;
97         break;
98       }
99     }
100   }
101
102   if(result == NULL && (mode == Exception::Mode::Throw || mode == Exception::Mode::Trace)) {
103     string msg(asString());
104     msg += " | Parameter '";
105     msg += name;
106     msg += "' not found";
107     RuntimeException ex(msg, ANNA_FILE_LOCATION);
108
109     if(mode == Exception::Mode::Throw)
110       throw ex;
111
112     ex.trace();
113   }
114
115   return result;
116 }
117
118 const char* http::wims20::ServerSide::getCStringValue(const char* name, const Exception::Mode::_v mode) const
119 noexcept(false) {
120   const string* temp = getValue(name, mode);
121   return (temp == NULL) ? NULL : temp->c_str();
122 }
123
124 int http::wims20::ServerSide::getIntegerValue(const char* name, const Exception::Mode::_v mode) const
125 noexcept(false) {
126   const string* tmp = getValue(name, mode);
127
128   if(tmp == NULL)
129     return 0;
130
131   const char* value = tmp->c_str();
132   return (anna_strncmp(value, "0x", 2) == 0) ? strtol(value + 2, NULL, 16) :  atoi(value);
133 }
134
135 /* Nos ha debido llegar algo asi como: serviceID/guid {other_possible_levels}
136  */
137 void http::wims20::ServerSide::decodeHierarchy(const std::string& hierarchy)
138 noexcept(false) {
139   const Tokenizer& items = split(SplitCode::HierarchyItem, hierarchy);
140   Abstract::setServiceID(items [0]);
141   Abstract::setGUID(items [1]);
142
143   if(items.size() > 2) {
144     Tokenizer::const_iterator maxii, ii = items.begin();
145     ii ++;
146     ii ++;
147
148     for(maxii = items.end(); ii != maxii; ii ++)
149       Abstract::other_level_add(Tokenizer::data(ii));
150   }
151 }
152
153 /* Nos ha debido llegar algo así como: name=value&*{nameN=valueN}
154  */
155 void http::wims20::ServerSide::decodeParameters(const std::string& parameters)
156 noexcept(false) {
157   const Tokenizer& tkparams = split(SplitCode::Parameters, parameters);
158
159   for(Tokenizer::const_iterator ii = tkparams.begin(), maxii = tkparams.end(); ii != maxii; ii ++) {
160     const string& parameter = Tokenizer::data(ii);
161     // Separa los XXX=YYYY
162     const Tokenizer& tkparam = split(SplitCode::ParameterAndArgument, parameter);
163     Abstract::parameter_set(tkparam [0], tkparam [1]);
164   }
165 }
166
167 const Tokenizer& http::wims20::ServerSide::split(const SplitCode::_v splitZone, const std::string& str)
168 noexcept(false) {
169   static const char* separator [] = { "?", "/", "&", "=", NULL };
170   a_tokenizer [splitZone].apply(str, separator [splitZone]);
171   LOGDEBUG(
172     string msg("String: ");
173     msg += str;
174     msg += " | Separator: ";
175     msg += separator [splitZone];
176     Logger::debug(msg, ANNA_FILE_LOCATION);
177   );
178   return a_tokenizer [splitZone];
179 }
180