Updated Makefiles and CMakeLists.txt to point to resource, not oic-resource
[platform/upstream/iotivity.git] / resource / src / OCUtilities.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <OCApi.h>
22
23 #include "OCUtilities.h"
24
25 #include <boost/algorithm/string.hpp>
26
27 #include <sstream>
28 #include <iterator>
29 #include <algorithm>
30
31 extern "C" {
32 #include <uri.h>    // libcoap
33 #include <option.h> // libcoap
34 }
35
36 namespace OC {
37
38     // Helper function to escape special character.
39     std::string escapeString(const std::string& value)
40     {
41         std::ostringstream stringStream;
42         for (const char& c : value)
43         {
44             switch (c)
45             {
46                 case '\\': stringStream << "\\\\";
47                     break;
48                 case '"': stringStream << "\\\"";
49                     break;
50                 case '/': stringStream << "\\/";
51                     break;
52                 case '\b': stringStream << "\\b";
53                     break;
54                 case '\f': stringStream << "\\f";
55                     break;
56                 case '\n': stringStream << "\\n";
57                     break;
58                 case '\r': stringStream << "\\r";
59                     break;
60                 case '\t': stringStream << "\\t";
61                     break;
62                 default: stringStream << c;
63                     break;
64            }
65         }
66         return stringStream.str();
67     }
68 }
69 // [TODO] remove this function
70 // it seems that the C stack is parsing and giving out the query separately.
71 // the entire URI need not be parsed
72 static OC::Utilities::QueryParamsKeyVal tempPatch(const std::string& _uri)
73 {
74     OC::Utilities::QueryParamsKeyVal qp;
75     if(_uri.empty())
76     {
77         return qp;
78     }
79
80     std::vector<std::string> queryparams;
81     boost::split(queryparams, _uri, boost::is_any_of("&"));
82
83     for(std::string& it: queryparams)
84     {
85         std::vector<std::string> keyval;
86         boost::split(keyval, it, boost::is_any_of("="));
87         if(2 == keyval.size())
88         {
89             qp[keyval.at(0)] = keyval.at(1);
90         }
91     }
92
93     return qp;
94 }
95
96 // implementation can be split into two functions if needed
97 // uses do{}while(0) to avoid returning from multiple locations
98 OC::Utilities::QueryParamsKeyVal OC::Utilities::getQueryParams(const std::string& _uri)
99 {
100
101     // this is a temporary fix. [TODO] remove this after permanent fix
102     return tempPatch(_uri);
103
104     OC::Utilities::QueryParamsKeyVal qp;
105     unsigned char *bufptr = nullptr; // don't delete via bufptr
106     unsigned char *bufptrToDelete = nullptr; // bufptr may be incremented. need this one to keep track.
107     do // while(0)
108     {
109         if(_uri.empty())
110         {
111             break;
112         }
113
114         coap_uri_t coapuri = {{0}};
115         unsigned char* uristr = reinterpret_cast<unsigned char*>(const_cast<char*>(_uri.c_str()));
116
117         if(coap_split_uri(uristr, _uri.length(), &coapuri) < 0)
118         {
119             break;
120         }
121
122         size_t buflen = 2048; // this is big enough buffer. [TODO] may want to downsize it. I have seen that the size may have to be greater than coap.query.length, which is counterintuitve but there may be a bug in coap uri parser.
123         bufptrToDelete = bufptr = new (std::nothrow) unsigned char[buflen](); // why heap? will need it for incrementing the pointer in the logic below
124
125         if(!bufptr)
126         {
127             break;
128         }
129
130         int segments = -1;
131         if((segments = coap_split_query(coapuri.query.s, coapuri.query.length, bufptr, &buflen)) < 0)
132         {
133             break;
134         }
135
136         // coap uri parser has weird api. its not straighforward to understand what the coap function calls below do.
137         // coap uri parser lacks ability to split the key value pair in query params. that will be done in getQueryParams() function
138         std::vector<std::string> queryparams;
139         while(segments--)
140         {
141             queryparams.push_back(std::string (reinterpret_cast<char*>(coap_opt_value(bufptr)), coap_opt_length(bufptr)));
142             bufptr += coap_opt_size(bufptr);
143         }
144
145         if(queryparams.empty())
146         {
147             break;
148         }
149
150         //[TODO] use foreach
151         for(std::string& it : queryparams)
152         {
153             std::vector<std::string> keyval;
154             boost::split(keyval, it, boost::is_any_of("="));
155             if(2 == keyval.size())
156             {
157                 qp[keyval.at(0)] = keyval.at(1);
158             }
159         }
160     }
161     while(0);
162
163     if(bufptrToDelete)
164     {
165         delete [] bufptrToDelete;
166     }
167     return qp;
168 }
169
170 namespace OC {
171
172 OCStackResult result_guard(const OCStackResult r)
173 {
174  std::ostringstream os;
175
176  switch(r)
177  {
178     default:
179         os << "result_guard(): unhandled exception: " << OCException::reason(r);
180         throw OCException(os.str(), r);
181
182     /* Exceptional conditions: */
183     case OC_STACK_NO_MEMORY:
184     case OC_STACK_COMM_ERROR:
185     case OC_STACK_NOTIMPL:
186     case OC_STACK_INVALID_URI:
187     case OC_STACK_INVALID_QUERY:
188     case OC_STACK_INVALID_IP:
189     case OC_STACK_INVALID_PORT:
190     case OC_STACK_INVALID_CALLBACK:
191     case OC_STACK_INVALID_METHOD:
192     case OC_STACK_INVALID_PARAM:
193     case OC_STACK_INVALID_OBSERVE_PARAM:
194         os << "result_guard(): " << r << ": " << OCException::reason(r);
195         throw OCException(os.str(), r);
196
197     /* Non-exceptional failures or success: */
198     case OC_STACK_OK:
199     case OC_STACK_NO_RESOURCE:
200     case OC_STACK_RESOURCE_ERROR:
201     case OC_STACK_SLOW_RESOURCE:
202     case OC_STACK_NO_OBSERVERS:
203     case OC_STACK_OBSERVER_NOT_FOUND:
204     case OC_STACK_OBSERVER_NOT_ADDED:
205     case OC_STACK_OBSERVER_NOT_REMOVED:
206 #ifdef WITH_PRESENCE
207     case OC_STACK_PRESENCE_STOPPED:
208     case OC_STACK_PRESENCE_DO_NOT_HANDLE:
209 #endif
210
211     break;
212  }
213
214  return r;
215 }
216
217 } // namespace OC