source: azure_iot_hub/trunk/azure_iothub/c-utility/src/httpheaders.c@ 389

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

ビルドが通るよう更新

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