Coverage Report

Created: 2026-10-17 06:10

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
272
#define URI_PREFIX_SEP "://"
29
9.47k
#define URI_HOSTNAME_SEP ":"
30
163
#define URI_PORT_SEP "/"
31
32
18.2k
#define URI_OPEN_BRACKET '['
33
9.38k
#define URI_CLOSE_BRACKET ']'
34
35
159
#define TCPUA_PREFIX ((const char*) "opc.tcp")
36
158
#define UDPUA_PREFIX ((const char*) "opc.udp")
37
157
#define ETHUA_PREFIX ((const char*) "opc.eth")
38
156
#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
268
{
67
268
    if (NULL == ppCursor || NULL == *ppCursor || NULL == ppHostname || NULL != *ppHostname)
68
0
    {
69
0
        return (SOPC_STATUS_INVALID_PARAMETERS);
70
0
    }
71
72
268
    const char* start = *ppCursor;
73
268
    const char* pCursor = *ppCursor;
74
268
    SOPC_ReturnStatus res = SOPC_STATUS_OK;
75
268
    bool match = false;
76
268
    char* resStr = NULL;
77
268
    size_t len = 0;
78
268
    size_t NbBracketOpen = 0;
79
80
18.7k
    while (!match && res == SOPC_STATUS_OK)
81
18.4k
    {
82
18.4k
        if (0 == NbBracketOpen)
83
9.31k
        {
84
9.31k
            match = strchr(URI_HOSTNAME_SEP, *pCursor) != NULL;
85
9.31k
        }
86
18.4k
        if (!match)
87
18.2k
        {
88
18.2k
            if (*pCursor == URI_OPEN_BRACKET)
89
8.78k
            {
90
8.78k
                ++start;
91
8.78k
                ++NbBracketOpen;
92
8.78k
            }
93
18.2k
            if (NbBracketOpen > 0 && URI_CLOSE_BRACKET == *pCursor)
94
380
            {
95
380
                --len;
96
380
                --NbBracketOpen;
97
380
            }
98
17.8k
            else
99
17.8k
            {
100
17.8k
                ++len;
101
17.8k
            }
102
18.2k
            ++pCursor;
103
18.2k
        }
104
18.4k
        if ('\0' == *pCursor)
105
104
        {
106
104
            res = SOPC_STATUS_INVALID_PARAMETERS;
107
104
        }
108
18.4k
    }
109
268
    if (NbBracketOpen > 0 || 0 == len)
110
66
    {
111
66
        res = SOPC_STATUS_INVALID_PARAMETERS;
112
66
    }
113
268
    if (SOPC_STATUS_OK == res)
114
163
    {
115
163
        resStr = SOPC_Calloc(len + 1, sizeof(char));
116
163
        if (NULL == resStr)
117
0
        {
118
0
            res = SOPC_STATUS_OUT_OF_MEMORY;
119
0
        }
120
163
    }
121
268
    if (SOPC_STATUS_OK == res)
122
163
    {
123
163
        resStr = strncpy(resStr, start, len);
124
163
        *ppHostname = resStr;
125
163
        pCursor += strlen(URI_HOSTNAME_SEP);
126
163
        *ppCursor = pCursor;
127
163
    }
128
268
    return (res);
129
268
}
130
131
static SOPC_ReturnStatus getUriPrefixOrPort(const char** ppCursor,
132
                                            char** ppFind,
133
                                            const char* sep_match,
134
                                            SOPC_UriSwitch uriSwitch)
135
435
{
136
435
    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
435
    const char* start = *ppCursor;
142
435
    const char* pCursor = *ppCursor;
143
435
    SOPC_ReturnStatus res = SOPC_STATUS_OK;
144
435
    char* resStr = NULL;
145
435
    size_t len = 0;
146
147
435
    pCursor = strstr(start, sep_match);
148
435
    if (SOPC_URI_PREFIX == uriSwitch)
149
272
    {
150
272
        if (NULL == pCursor)
151
3
        {
152
3
            res = SOPC_STATUS_INVALID_PARAMETERS;
153
3
        }
154
272
    }
155
163
    else if (SOPC_URI_PORT == uriSwitch)
156
163
    {
157
163
        if (NULL == pCursor)
158
156
        {
159
156
            pCursor = start + strlen(start);
160
156
        }
161
163
    }
162
0
    else
163
0
    {
164
0
        SOPC_ASSERT(false && "Unknown uriSwitch");
165
0
    }
166
167
435
    if (SOPC_STATUS_OK == res)
168
432
    {
169
432
        if (pCursor > start)
170
427
        {
171
427
            len = (size_t)(pCursor - start);
172
427
        }
173
5
        else
174
5
        {
175
5
            res = SOPC_STATUS_INVALID_PARAMETERS;
176
5
        }
177
432
    }
178
179
435
    if (SOPC_STATUS_OK == res)
180
427
    {
181
427
        resStr = SOPC_Calloc(len + 1, sizeof(char));
182
427
        if (NULL == resStr)
183
0
        {
184
0
            res = SOPC_STATUS_OUT_OF_MEMORY;
185
0
        }
186
427
    }
187
188
435
    if (SOPC_STATUS_OK == res)
189
427
    {
190
427
        resStr = strncpy(resStr, start, len);
191
427
        pCursor += strlen(sep_match);
192
427
        *ppFind = resStr;
193
427
        *ppCursor = pCursor;
194
427
    }
195
435
    return (res);
196
435
}
197
198
static SOPC_ReturnStatus getUriTypeFromEnum(char** prefix, SOPC_UriType* type)
199
159
{
200
159
    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
158
    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
157
    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
156
    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
155
    return (SOPC_STATUS_INVALID_PARAMETERS);
221
159
}
222
223
SOPC_ReturnStatus SOPC_Helper_URI_SplitUri(const char* uri, SOPC_UriType* type, char** hostname, char** port)
224
294
{
225
294
    if (NULL == uri || NULL == hostname || NULL == port || NULL != *port || NULL != *hostname)
226
0
    {
227
0
        return (SOPC_STATUS_INVALID_PARAMETERS);
228
0
    }
229
294
    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
272
    const char* pCursor = uri;
237
272
    char* prefix = NULL;
238
272
    SOPC_ReturnStatus result = SOPC_STATUS_OK;
239
240
272
    if (SOPC_STATUS_OK == result)
241
272
    {
242
272
        result = getUriPrefixOrPort(&pCursor, &prefix, URI_PREFIX_SEP, SOPC_URI_PREFIX);
243
272
    }
244
272
    if (SOPC_STATUS_OK == result)
245
268
    {
246
268
        result = getUriHostname(&pCursor, hostname);
247
268
    }
248
272
    if (SOPC_STATUS_OK == result)
249
163
    {
250
163
        result = getUriPrefixOrPort(&pCursor, port, URI_PORT_SEP, SOPC_URI_PORT);
251
163
    }
252
272
    if (SOPC_STATUS_OK == result)
253
159
    {
254
159
        result = getUriTypeFromEnum(&prefix, type);
255
159
    }
256
272
    SOPC_Free(prefix);
257
272
    if (SOPC_STATUS_OK != result)
258
268
    {
259
268
        SOPC_Free(*hostname);
260
268
        SOPC_Free(*port);
261
268
        *hostname = NULL;
262
        *port = NULL;
263
268
    }
264
272
    return (result);
265
294
}