1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "lib/url/url.hpp"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "core/common/code_utils.hpp"
36 
37 namespace ot {
38 namespace Url {
39 
Url(void)40 Url::Url(void)
41 {
42     mProtocol = nullptr;
43     mPath     = nullptr;
44     mQuery    = nullptr;
45     mEnd      = nullptr;
46 }
47 
Init(char * aUrl)48 otError Url::Init(char *aUrl)
49 {
50     otError error = OT_ERROR_NONE;
51     char   *url   = aUrl;
52 
53     mEnd      = aUrl + strlen(aUrl);
54     mProtocol = aUrl;
55 
56     url = strstr(aUrl, "://");
57     VerifyOrExit(url != nullptr, error = OT_ERROR_PARSE);
58     *url = '\0';
59     url += sizeof("://") - 1;
60     mPath = url;
61 
62     url = strstr(url, "?");
63 
64     if (url != nullptr)
65     {
66         mQuery = ++url;
67 
68         for (char *cur = strtok(url, "&"); cur != nullptr; cur = strtok(nullptr, "&"))
69         {
70             cur[-1] = '\0';
71         }
72     }
73     else
74     {
75         mQuery = mEnd;
76     }
77 
78 exit:
79     return error;
80 }
81 
GetValue(const char * aName,const char * aLastValue) const82 const char *Url::GetValue(const char *aName, const char *aLastValue) const
83 {
84     const char  *rval = nullptr;
85     const size_t len  = strlen(aName);
86     const char  *start;
87 
88     if (aLastValue == nullptr)
89     {
90         start = mQuery;
91     }
92     else
93     {
94         VerifyOrExit(aLastValue > mQuery && aLastValue < mEnd);
95         start = aLastValue + strlen(aLastValue) + 1;
96     }
97 
98     while (start < mEnd)
99     {
100         const char *last = nullptr;
101 
102         if (!strncmp(aName, start, len))
103         {
104             if (start[len] == '=')
105             {
106                 ExitNow(rval = &start[len + 1]);
107             }
108             else if (start[len] == '\0')
109             {
110                 ExitNow(rval = &start[len]);
111             }
112         }
113         last  = start;
114         start = last + strlen(last) + 1;
115     }
116 
117 exit:
118     return rval;
119 }
120 
ParseUint32(const char * aName,uint32_t & aValue) const121 otError Url::ParseUint32(const char *aName, uint32_t &aValue) const
122 {
123     otError     error = OT_ERROR_NONE;
124     const char *str;
125     long long   value;
126 
127     VerifyOrExit((str = GetValue(aName)) != nullptr, error = OT_ERROR_NOT_FOUND);
128 
129     value = strtoll(str, nullptr, 0);
130     VerifyOrExit(0 <= value && value <= UINT32_MAX, error = OT_ERROR_INVALID_ARGS);
131     aValue = static_cast<uint32_t>(value);
132 
133 exit:
134     return error;
135 }
136 
ParseUint16(const char * aName,uint16_t & aValue) const137 otError Url::ParseUint16(const char *aName, uint16_t &aValue) const
138 {
139     otError  error = OT_ERROR_NONE;
140     uint32_t value;
141 
142     SuccessOrExit(error = ParseUint32(aName, value));
143     VerifyOrExit(value <= UINT16_MAX, error = OT_ERROR_INVALID_ARGS);
144     aValue = static_cast<uint16_t>(value);
145 
146 exit:
147     return error;
148 }
149 
ParseUint8(const char * aName,uint8_t & aValue) const150 otError Url::ParseUint8(const char *aName, uint8_t &aValue) const
151 {
152     otError  error = OT_ERROR_NONE;
153     uint32_t value;
154 
155     SuccessOrExit(error = ParseUint32(aName, value));
156     VerifyOrExit(value <= UINT8_MAX, error = OT_ERROR_INVALID_ARGS);
157     aValue = static_cast<uint8_t>(value);
158 
159 exit:
160     return error;
161 }
162 
ParseInt32(const char * aName,int32_t & aValue) const163 otError Url::ParseInt32(const char *aName, int32_t &aValue) const
164 {
165     otError     error = OT_ERROR_NONE;
166     const char *str;
167     long long   value;
168 
169     VerifyOrExit((str = GetValue(aName)) != nullptr, error = OT_ERROR_NOT_FOUND);
170 
171     value = strtoll(str, nullptr, 0);
172     VerifyOrExit(INT32_MIN <= value && value <= INT32_MAX, error = OT_ERROR_INVALID_ARGS);
173     aValue = static_cast<int32_t>(value);
174 
175 exit:
176     return error;
177 }
178 
ParseInt16(const char * aName,int16_t & aValue) const179 otError Url::ParseInt16(const char *aName, int16_t &aValue) const
180 {
181     otError error = OT_ERROR_NONE;
182     int32_t value;
183 
184     SuccessOrExit(error = ParseInt32(aName, value));
185     VerifyOrExit(INT16_MIN <= value && value <= INT16_MAX, error = OT_ERROR_INVALID_ARGS);
186     aValue = static_cast<int16_t>(value);
187 
188 exit:
189     return error;
190 }
191 
ParseInt8(const char * aName,int8_t & aValue) const192 otError Url::ParseInt8(const char *aName, int8_t &aValue) const
193 {
194     otError error = OT_ERROR_NONE;
195     int32_t value;
196 
197     SuccessOrExit(error = ParseInt32(aName, value));
198     VerifyOrExit(INT8_MIN <= value && value <= INT8_MAX, error = OT_ERROR_INVALID_ARGS);
199     aValue = static_cast<int8_t>(value);
200 
201 exit:
202     return error;
203 }
204 
205 } // namespace Url
206 } // namespace ot
207