Coverage Report

Created: 2026-11-13 06:19

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