Coverage Report

Created: 2025-07-11 06:29

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