source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/src/httpheaders.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.3 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <string.h>
6#include "azure_macro_utils/macro_utils.h"
7#include "azure_c_shared_utility/gballoc.h"
8#include "azure_c_shared_utility/map.h"
9#include "azure_c_shared_utility/httpheaders.h"
10#include "azure_c_shared_utility/crt_abstractions.h"
11#include "azure_c_shared_utility/xlogging.h"
12
13MU_DEFINE_ENUM_STRINGS(HTTP_HEADERS_RESULT, HTTP_HEADERS_RESULT_VALUES);
14
15typedef struct HTTP_HEADERS_HANDLE_DATA_TAG
16{
17 MAP_HANDLE headers;
18} HTTP_HEADERS_HANDLE_DATA;
19
20HTTP_HEADERS_HANDLE HTTPHeaders_Alloc(void)
21{
22 /*Codes_SRS_HTTP_HEADERS_99_002:[ This API shall produce a HTTP_HANDLE that can later be used in subsequent calls to the module.]*/
23 HTTP_HEADERS_HANDLE_DATA* result;
24 result = (HTTP_HEADERS_HANDLE_DATA*)malloc(sizeof(HTTP_HEADERS_HANDLE_DATA));
25
26 if (result == NULL)
27 {
28 LogError("malloc failed");
29 }
30 else
31 {
32 /*Codes_SRS_HTTP_HEADERS_99_004:[ After a successful init, HTTPHeaders_GetHeaderCount shall report 0 existing headers.]*/
33 result->headers = Map_Create(NULL);
34 if (result->headers == NULL)
35 {
36 LogError("Map_Create failed");
37 free(result);
38 result = NULL;
39 }
40 else
41 {
42 /*all is fine*/
43 }
44 }
45
46 /*Codes_SRS_HTTP_HEADERS_99_003:[ The function shall return NULL when the function cannot execute properly]*/
47 return (HTTP_HEADERS_HANDLE)result;
48}
49
50/*Codes_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/
51void HTTPHeaders_Free(HTTP_HEADERS_HANDLE handle)
52{
53 /*Codes_SRS_HTTP_HEADERS_02_001: [If httpHeadersHandle is NULL then HTTPHeaders_Free shall perform no action.] */
54 if (handle == NULL)
55 {
56 /*do nothing*/
57 }
58 else
59 {
60 /*Codes_SRS_HTTP_HEADERS_99_005:[ Calling this API shall de-allocate the data structures allocated by previous API calls to the same handle.]*/
61 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle;
62
63 Map_Destroy(handleData->headers);
64 free(handleData);
65 }
66}
67
68/*Codes_SRS_HTTP_HEADERS_99_012:[ Calling this API shall record a header from name and value parameters.]*/
69static HTTP_HEADERS_RESULT headers_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE handle, const char* name, const char* value, bool replace)
70{
71 HTTP_HEADERS_RESULT result;
72 /*Codes_SRS_HTTP_HEADERS_99_014:[ The function shall return when the handle is not valid or when name parameter is NULL or when value parameter is NULL.]*/
73 if (
74 (handle == NULL) ||
75 (name == NULL) ||
76 (value == NULL)
77 )
78 {
79 result = HTTP_HEADERS_INVALID_ARG;
80 LogError("invalid arg (NULL) , result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
81 }
82 else
83 {
84 /*Codes_SRS_HTTP_HEADERS_99_036:[ If name contains the characters outside character codes 33 to 126 then the return value shall be HTTP_HEADERS_INVALID_ARG]*/
85 /*Codes_SRS_HTTP_HEADERS_99_031:[ If name contains the character ":" then the return value shall be HTTP_HEADERS_INVALID_ARG.]*/
86 size_t i;
87 size_t nameLen = strlen(name);
88 for (i = 0; i < nameLen; i++)
89 {
90 if ((name[i] < 33) || (126 < name[i]) || (name[i] == ':'))
91 {
92 break;
93 }
94 }
95
96 if (i < nameLen)
97 {
98 result = HTTP_HEADERS_INVALID_ARG;
99 LogError("(result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
100 }
101 else
102 {
103 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle;
104 const char* existingValue = Map_GetValueFromKey(handleData->headers, name);
105 /*eat up the whitespaces from value, as per RFC 2616, chapter 4.2 "The field value MAY be preceded by any amount of LWS, though a single SP is preferred."*/
106 /*Codes_SRS_HTTP_HEADERS_02_002: [The LWS from the beginning of the value shall not be stored.] */
107 while ((value[0] == ' ') || (value[0] == '\t') || (value[0] == '\r') || (value[0] == '\n'))
108 {
109 value++;
110 }
111
112 if (!replace && (existingValue != NULL))
113 {
114 size_t existingValueLen = strlen(existingValue);
115 size_t valueLen = strlen(value);
116 char* newValue = (char*)malloc(sizeof(char) * (existingValueLen + /*COMMA_AND_SPACE_LENGTH*/ 2 + valueLen + /*EOL*/ 1));
117 if (newValue == NULL)
118 {
119 /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/
120 result = HTTP_HEADERS_ALLOC_FAILED;
121 LogError("failed to malloc , result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
122 }
123 else
124 {
125 char* runNewValue;
126 /*Codes_SRS_HTTP_HEADERS_99_017:[ If the name already exists in the collection of headers, the function shall concatenate the new value after the existing value, separated by a comma and a space as in: old-value+", "+new-value.]*/
127 (void)memcpy(newValue, existingValue, existingValueLen);
128 runNewValue = newValue + existingValueLen;
129 (*runNewValue++) = ',';
130 (*runNewValue++) = ' ';
131 (void)memcpy(runNewValue, value, valueLen + /*EOL*/ 1);
132
133 /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/
134 if (Map_AddOrUpdate(handleData->headers, name, newValue) != MAP_OK)
135 {
136 /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/
137 result = HTTP_HEADERS_ERROR;
138 LogError("failed to Map_AddOrUpdate, result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
139 }
140 else
141 {
142 /*Codes_SRS_HTTP_HEADERS_99_013:[ The function shall return HTTP_HEADERS_OK when execution is successful.]*/
143 result = HTTP_HEADERS_OK;
144 }
145 free(newValue);
146 }
147 }
148 else
149 {
150 /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/
151 if (Map_AddOrUpdate(handleData->headers, name, value) != MAP_OK)
152 {
153 /*Codes_SRS_HTTP_HEADERS_99_015:[ The function shall return HTTP_HEADERS_ALLOC_FAILED when an internal request to allocate memory fails.]*/
154 result = HTTP_HEADERS_ALLOC_FAILED;
155 LogError("failed to Map_AddOrUpdate, result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
156 }
157 else
158 {
159 result = HTTP_HEADERS_OK;
160 }
161 }
162 }
163 }
164
165 return result;
166}
167
168HTTP_HEADERS_RESULT HTTPHeaders_AddHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value)
169{
170 return headers_ReplaceHeaderNameValuePair(httpHeadersHandle, name, value, false);
171}
172
173/* Codes_SRS_HTTP_HEADERS_06_001: [This API will perform exactly as HTTPHeaders_AddHeaderNameValuePair except that if the header name already exists the already existing value will be replaced as opposed to concatenated to.] */
174HTTP_HEADERS_RESULT HTTPHeaders_ReplaceHeaderNameValuePair(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name, const char* value)
175{
176 return headers_ReplaceHeaderNameValuePair(httpHeadersHandle, name, value, true);
177}
178
179
180const char* HTTPHeaders_FindHeaderValue(HTTP_HEADERS_HANDLE httpHeadersHandle, const char* name)
181{
182 const char* result;
183 /*Codes_SRS_HTTP_HEADERS_99_022:[ The return value shall be NULL if name parameter is NULL or if httpHeadersHandle is NULL]*/
184 if (
185 (httpHeadersHandle == NULL) ||
186 (name == NULL)
187 )
188 {
189 result = NULL;
190 }
191 else
192 {
193 /*Codes_SRS_HTTP_HEADERS_99_018:[ Calling this API shall retrieve the value for a previously stored name.]*/
194 /*Codes_SRS_HTTP_HEADERS_99_020:[ The return value shall be different than NULL when the name matches the name of a previously stored name:value pair.] */
195 /*Codes_SRS_HTTP_HEADERS_99_021:[ In this case the return value shall point to a string that shall strcmp equal to the original stored string.]*/
196 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)httpHeadersHandle;
197 result = Map_GetValueFromKey(handleData->headers, name);
198 }
199 return result;
200
201}
202
203HTTP_HEADERS_RESULT HTTPHeaders_GetHeaderCount(HTTP_HEADERS_HANDLE handle, size_t* headerCount)
204{
205 HTTP_HEADERS_RESULT result;
206 /*Codes_SRS_HTTP_HEADERS_99_024:[ The function shall return HTTP_HEADERS_INVALID_ARG when an invalid handle is passed.]*/
207 /*Codes_SRS_HTTP_HEADERS_99_025:[ The function shall return HTTP_HEADERS_INVALID_ARG when headersCount is NULL.]*/
208 if ((handle == NULL) ||
209 (headerCount == NULL))
210 {
211 result = HTTP_HEADERS_INVALID_ARG;
212 LogError("(result = %" PRI_MU_ENUM ")", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
213 }
214 else
215 {
216 HTTP_HEADERS_HANDLE_DATA *handleData = (HTTP_HEADERS_HANDLE_DATA *)handle;
217 const char*const* keys;
218 const char*const* values;
219 /*Codes_SRS_HTTP_HEADERS_99_023:[ Calling this API shall provide the number of stored headers.]*/
220 if (Map_GetInternals(handleData->headers, &keys, &values, headerCount) != MAP_OK)
221 {
222 /*Codes_SRS_HTTP_HEADERS_99_037:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs.]*/
223 result = HTTP_HEADERS_ERROR;
224 LogError("Map_GetInternals failed, result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
225 }
226 else
227 {
228 /*Codes_SRS_HTTP_HEADERS_99_026:[ The function shall write in *headersCount the number of currently stored headers and shall return HTTP_HEADERS_OK]*/
229 result = HTTP_HEADERS_OK;
230 }
231 }
232
233 return result;
234}
235
236/*produces a string in *destination that is equal to name: value*/
237HTTP_HEADERS_RESULT HTTPHeaders_GetHeader(HTTP_HEADERS_HANDLE handle, size_t index, char** destination)
238{
239 HTTP_HEADERS_RESULT result = HTTP_HEADERS_OK;
240
241 /*Codes_SRS_HTTP_HEADERS_99_028:[ The function shall return NULL if the handle is invalid.]*/
242 /*Codes_SRS_HTTP_HEADERS_99_032:[ The function shall return HTTP_HEADERS_INVALID_ARG if the destination is NULL]*/
243 if (
244 (handle == NULL) ||
245 (destination == NULL)
246 )
247 {
248 result = HTTP_HEADERS_INVALID_ARG;
249 LogError("invalid arg (NULL), result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
250 }
251 /*Codes_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/
252 else
253 {
254 HTTP_HEADERS_HANDLE_DATA* handleData = (HTTP_HEADERS_HANDLE_DATA*)handle;
255 const char*const* keys;
256 const char*const* values;
257 size_t headerCount;
258 if (Map_GetInternals(handleData->headers, &keys, &values, &headerCount) != MAP_OK)
259 {
260 /*Codes_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/
261 result = HTTP_HEADERS_ERROR;
262 LogError("Map_GetInternals failed, result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
263 }
264 else
265 {
266 /*Codes_SRS_HTTP_HEADERS_99_029:[ The function shall return HTTP_HEADERS_INVALID_ARG if index is not valid (for example, out of range) for the currently stored headers.]*/
267 if (index >= headerCount)
268 {
269 result = HTTP_HEADERS_INVALID_ARG;
270 LogError("index out of bounds, result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
271 }
272 else
273 {
274 size_t keyLen = strlen(keys[index]);
275 size_t valueLen = strlen(values[index]);
276 *destination = (char*)malloc(sizeof(char) * (keyLen + /*COLON_AND_SPACE_LENGTH*/ 2 + valueLen + /*EOL*/ 1));
277 if (*destination == NULL)
278 {
279 /*Codes_SRS_HTTP_HEADERS_99_034:[ The function shall return HTTP_HEADERS_ERROR when an internal error occurs]*/
280 result = HTTP_HEADERS_ERROR;
281 LogError("unable to malloc, result= %" PRI_MU_ENUM "", MU_ENUM_VALUE(HTTP_HEADERS_RESULT, result));
282 }
283 else
284 {
285 /*Codes_SRS_HTTP_HEADERS_99_016:[ The function shall store the name:value pair in such a way that when later retrieved by a call to GetHeader it will return a string that shall strcmp equal to the name+": "+value.]*/
286 /*Codes_SRS_HTTP_HEADERS_99_027:[ Calling this API shall produce the string value+": "+pair) for the index header in the *destination parameter.]*/
287 char* runDestination = (*destination);
288 (void)memcpy(runDestination, keys[index], keyLen);
289 runDestination += keyLen;
290 (*runDestination++) = ':';
291 (*runDestination++) = ' ';
292 (void)memcpy(runDestination, values[index], valueLen + /*EOL*/ 1);
293 /*Codes_SRS_HTTP_HEADERS_99_035:[ The function shall return HTTP_HEADERS_OK when the function executed without error.]*/
294 result = HTTP_HEADERS_OK;
295 }
296 }
297 }
298 }
299
300 return result;
301}
302
303HTTP_HEADERS_HANDLE HTTPHeaders_Clone(HTTP_HEADERS_HANDLE handle)
304{
305 HTTP_HEADERS_HANDLE_DATA* result;
306 /*Codes_SRS_HTTP_HEADERS_02_003: [If handle is NULL then HTTPHeaders_Clone shall return NULL.] */
307 if (handle == NULL)
308 {
309 result = NULL;
310 }
311 else
312 {
313 /*Codes_SRS_HTTP_HEADERS_02_004: [Otherwise HTTPHeaders_Clone shall clone the content of handle to a new handle.] */
314 result = (HTTP_HEADERS_HANDLE_DATA*)malloc(sizeof(HTTP_HEADERS_HANDLE_DATA));
315 if (result == NULL)
316 {
317 /*Codes_SRS_HTTP_HEADERS_02_005: [If cloning fails for any reason, then HTTPHeaders_Clone shall return NULL.] */
318 }
319 else
320 {
321 HTTP_HEADERS_HANDLE_DATA* handleData = handle;
322 result->headers = Map_Clone(handleData->headers);
323 if (result->headers == NULL)
324 {
325 /*Codes_SRS_HTTP_HEADERS_02_005: [If cloning fails for any reason, then HTTPHeaders_Clone shall return NULL.] */
326 free(result);
327 result = NULL;
328 }
329 else
330 {
331 /*all is fine*/
332 }
333 }
334 }
335 return result;
336}
Note: See TracBrowser for help on using the repository browser.