Coverage Report

Created: 2025-11-04 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/S2OPC/src/Common/helpers/sopc_helper_uri.c
Line
Count
Source
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include <stddef.h>
21
#include <string.h>
22
23
#include "sopc_assert.h"
24
#include "sopc_helper_string.h"
25
#include "sopc_helper_uri.h"
26
#include "sopc_mem_alloc.h"
27
28
261
#define URI_PREFIX_SEP "://"
29
6.54k
#define URI_HOSTNAME_SEP ":"
30
156
#define URI_PORT_SEP "/"
31
32
20.3k
#define URI_OPEN_BRACKET '['
33
14.3k
#define URI_CLOSE_BRACKET ']'
34
35
154
#define TCPUA_PREFIX ((const char*) "opc.tcp")
36
153
#define UDPUA_PREFIX ((const char*) "opc.udp")
37
152
#define ETHUA_PREFIX ((const char*) "opc.eth")
38
151
#define MQTTUA_PREFIX ((const char*) "MqttUa")
39
40
/**
41
 * Match prefix with SOPC existing prefix set the type with a SOPC_UriType and return true otherwise return false
42
 */
43
static SOPC_ReturnStatus getUriTypeFromEnum(char** prefix, SOPC_UriType* type);
44
45
/**
46
 * Extract Hostname from given URI
47
 * Must take a *pCursor which strictly start at the beginning of the sequence and a hostname with *hostname pointing to
48
 * NULL.
49
 * In case of failure parameters are not modified
50
 */
51
static SOPC_ReturnStatus getUriHostname(const char** ppCursor, char** ppHostname);
52
53
/**
54
 * Extract prefix or port from given URI depending on sep_match
55
 * Must take a *pCursor which strictly start at the beginning of the sequence and a port or prefix with *port or *prefix
56
 * pointing to NULL.
57
 * uriSwitch specify if we are looking for a port or a prefix.
58
 * In case of failure parameters are not modified
59
 */
60
static SOPC_ReturnStatus getUriPrefixOrPort(const char** ppCursor,
61
                                            char** ppFind,
62
                                            const char* sep_match,
63
                                            SOPC_UriSwitch uriSwitch);
64
65
static SOPC_ReturnStatus getUriHostname(const char** ppCursor, char** ppHostname)
66
256
{
67
256
    if (NULL == ppCursor || NULL == *ppCursor || NULL == ppHostname || NULL != *ppHostname)
68
0
    {
69
0
        return (SOPC_STATUS_INVALID_PARAMETERS);
70
0
    }
71
72
256
    const char* start = *ppCursor;
73
256
    const char* pCursor = *ppCursor;
74
256
    SOPC_ReturnStatus res = SOPC_STATUS_OK;
75
256
    bool match = false;
76
256
    char* resStr = NULL;
77
256
    size_t len = 0;
78
256
    size_t NbBracketOpen = 0;
79
80
20.7k
    while (!match && res == SOPC_STATUS_OK)
81
20.5k
    {
82
20.5k
        if (0 == NbBracketOpen)
83
6.38k
        {
84
6.38k
            match = strchr(URI_HOSTNAME_SEP, *pCursor) != NULL;
85
6.38k
        }
86
20.5k
        if (!match)
87
20.3k
        {
88
20.3k
            if (*pCursor == URI_OPEN_BRACKET)
89
9.86k
            {
90
9.86k
                ++start;
91
9.86k
                ++NbBracketOpen;
92
9.86k
            }
93
20.3k
            if (NbBracketOpen > 0 && URI_CLOSE_BRACKET == *pCursor)
94
388
            {
95
388
                --len;
96
388
                --NbBracketOpen;
97
388
            }
98
19.9k
            else
99
19.9k
            {
100
19.9k
                ++len;
101
19.9k
            }
102
20.3k
            ++pCursor;
103
20.3k
        }
104
20.5k
        if ('\0' == *pCursor)
105
99
        {
106
99
            res = SOPC_STATUS_INVALID_PARAMETERS;
107
99
        }
108
20.5k
    }
109
256
    if (NbBracketOpen > 0 || 0 == len)
110
65
    {
111
65
        res = SOPC_STATUS_INVALID_PARAMETERS;
112
65
    }
113
256
    if (SOPC_STATUS_OK == res)
114
156
    {
115
156
        resStr = SOPC_Calloc(len + 1, sizeof(char));
116
156
        if (NULL == resStr)
117
0
        {
118
0
            res = SOPC_STATUS_OUT_OF_MEMORY;
119
0
        }
120
156
    }
121
256
    if (SOPC_STATUS_OK == res)
122
156
    {
123
156
        resStr = strncpy(resStr, start, len);
124
156
        *ppHostname = resStr;
125
156
        pCursor += strlen(URI_HOSTNAME_SEP);
126
156
        *ppCursor = pCursor;
127
156
    }
128
256
    return (res);
129
256
}
130
131
static SOPC_ReturnStatus getUriPrefixOrPort(const char** ppCursor,
132
                                            char** ppFind,
133
                                            const char* sep_match,
134
                                            SOPC_UriSwitch uriSwitch)
135
417
{
136
417
    if (NULL == ppCursor || NULL == *ppCursor || NULL == ppFind || NULL != *ppFind || NULL == sep_match)
137
0
    {
138
0
        return (SOPC_STATUS_INVALID_PARAMETERS);
139
0
    }
140
141
417
    const char* start = *ppCursor;
142
417
    const char* pCursor = *ppCursor;
143
417
    SOPC_ReturnStatus res = SOPC_STATUS_OK;
144
417
    char* resStr = NULL;
145
417
    size_t len = 0;
146
147
417
    pCursor = strstr(start, sep_match);
148
417
    if (SOPC_URI_PREFIX == uriSwitch)
149
261
    {
150
261
        if (NULL == pCursor)
151
4
        {
152
4
            res = SOPC_STATUS_INVALID_PARAMETERS;
153
4
        }
154
261
    }
155
156
    else if (SOPC_URI_PORT == uriSwitch)
156
156
    {
157
156
        if (NULL == pCursor)
158
153
        {
159
153
            pCursor = start + strlen(start);
160
153
        }
161
156
    }
162
0
    else
163
0
    {
164
0
        SOPC_ASSERT(false && "Unknown uriSwitch");
165
0
    }
166
167
417
    if (SOPC_STATUS_OK == res)
168
413
    {
169
413
        if (pCursor > start)
170
410
        {
171
410
            len = (size_t)(pCursor - start);
172
410
        }
173
3
        else
174
3
        {
175
3
            res = SOPC_STATUS_INVALID_PARAMETERS;
176
3
        }
177
413
    }
178
179
417
    if (SOPC_STATUS_OK == res)
180
410
    {
181
410
        resStr = SOPC_Calloc(len + 1, sizeof(char));
182
410
        if (NULL == resStr)
183
0
        {
184
0
            res = SOPC_STATUS_OUT_OF_MEMORY;
185
0
        }
186
410
    }
187
188
417
    if (SOPC_STATUS_OK == res)
189
410
    {
190
410
        resStr = strncpy(resStr, start, len);
191
410
        pCursor += strlen(sep_match);
192
410
        *ppFind = resStr;
193
410
        *ppCursor = pCursor;
194
410
    }
195
417
    return (res);
196
417
}
197
198
static SOPC_ReturnStatus getUriTypeFromEnum(char** prefix, SOPC_UriType* type)
199
154
{
200
154
    if (strncmp(*prefix, TCPUA_PREFIX, (strlen(*prefix) + 1)) == 0)
201
1
    {
202
1
        *type = SOPC_URI_TCPUA;
203
1
        return (SOPC_STATUS_OK);
204
1
    }
205
153
    else if (strncmp(*prefix, UDPUA_PREFIX, (strlen(*prefix) + 1)) == 0)
206
1
    {
207
1
        *type = SOPC_URI_UDPUA;
208
1
        return (SOPC_STATUS_OK);
209
1
    }
210
152
    else if (strncmp(*prefix, ETHUA_PREFIX, (strlen(*prefix) + 1)) == 0)
211
1
    {
212
1
        *type = SOPC_URI_ETHUA;
213
1
        return (SOPC_STATUS_OK);
214
1
    }
215
151
    else if (strncmp(*prefix, MQTTUA_PREFIX, (strlen(*prefix) + 1)) == 0)
216
1
    {
217
1
        *type = SOPC_URI_MQTTUA;
218
1
        return (SOPC_STATUS_OK);
219
1
    }
220
150
    return (SOPC_STATUS_INVALID_PARAMETERS);
221
154
}
222
223
SOPC_ReturnStatus SOPC_Helper_URI_SplitUri(const char* uri, SOPC_UriType* type, char** hostname, char** port)
224
283
{
225
283
    if (NULL == uri || NULL == hostname || NULL == port || NULL != *port || NULL != *hostname)
226
0
    {
227
0
        return (SOPC_STATUS_INVALID_PARAMETERS);
228
0
    }
229
283
    if (strlen(uri) + 4 > TCP_UA_MAX_URL_LENGTH) // Encoded value shall be less than 4096 byte
230
22
    {
231
22
        return (SOPC_STATUS_INVALID_PARAMETERS);
232
22
    }
233
234
    /* *pCursor is a tmp copy to the uri. its purpose is to run through the URI
235
     * Its pos must be at the beginning of each sequence and must be strictly after the last separator found */
236
261
    const char* pCursor = uri;
237
261
    char* prefix = NULL;
238
261
    SOPC_ReturnStatus result = SOPC_STATUS_OK;
239
240
261
    if (SOPC_STATUS_OK == result)
241
261
    {
242
261
        result = getUriPrefixOrPort(&pCursor, &prefix, URI_PREFIX_SEP, SOPC_URI_PREFIX);
243
261
    }
244
261
    if (SOPC_STATUS_OK == result)
245
256
    {
246
256
        result = getUriHostname(&pCursor, hostname);
247
256
    }
248
261
    if (SOPC_STATUS_OK == result)
249
156
    {
250
156
        result = getUriPrefixOrPort(&pCursor, port, URI_PORT_SEP, SOPC_URI_PORT);
251
156
    }
252
261
    if (SOPC_STATUS_OK == result)
253
154
    {
254
154
        result = getUriTypeFromEnum(&prefix, type);
255
154
    }
256
261
    SOPC_Free(prefix);
257
261
    if (SOPC_STATUS_OK != result)
258
257
    {
259
257
        SOPC_Free(*hostname);
260
257
        SOPC_Free(*port);
261
257
        *hostname = NULL;
262
        *port = NULL;
263
257
    }
264
261
    return (result);
265
283
}