]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesProtocol.c
NetworkPkg: Fix suspicious dereference of pointer 'FieldCount'
[mirror_edk2.git] / NetworkPkg / HttpUtilitiesDxe / HttpUtilitiesProtocol.c
1 /** @file
2 Implementation of EFI_HTTP_PROTOCOL protocol interfaces.
3
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "HttpUtilitiesDxe.h"
16
17 EFI_HTTP_UTILITIES_PROTOCOL mHttpUtilitiesProtocol = {
18 HttpUtilitiesBuild,
19 HttpUtilitiesParse
20 };
21
22
23 /**
24 Create HTTP header based on a combination of seed header, fields
25 to delete, and fields to append.
26
27 The Build() function is used to manage the headers portion of an
28 HTTP message by providing the ability to add, remove, or replace
29 HTTP headers.
30
31 @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance.
32 @param[in] SeedMessageSize Size of the initial HTTP header. This can be zero.
33 @param[in] SeedMessage Initial HTTP header to be used as a base for
34 building a new HTTP header. If NULL,
35 SeedMessageSize is ignored.
36 @param[in] DeleteCount Number of null-terminated HTTP header field names
37 in DeleteList.
38 @param[in] DeleteList List of null-terminated HTTP header field names to
39 remove from SeedMessage. Only the field names are
40 in this list because the field values are irrelevant
41 to this operation.
42 @param[in] AppendCount Number of header fields in AppendList.
43 @param[in] AppendList List of HTTP headers to populate NewMessage with.
44 If SeedMessage is not NULL, AppendList will be
45 appended to the existing list from SeedMessage in
46 NewMessage.
47 @param[out] NewMessageSize Pointer to number of header fields in NewMessage.
48 @param[out] NewMessage Pointer to a new list of HTTP headers based on.
49
50 @retval EFI_SUCCESS Add, remove, and replace operations succeeded.
51 @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
52 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
53 This is NULL.
54 **/
55 EFI_STATUS
56 EFIAPI
57 HttpUtilitiesBuild (
58 IN EFI_HTTP_UTILITIES_PROTOCOL *This,
59 IN UINTN SeedMessageSize,
60 IN VOID *SeedMessage, OPTIONAL
61 IN UINTN DeleteCount,
62 IN CHAR8 *DeleteList[], OPTIONAL
63 IN UINTN AppendCount,
64 IN EFI_HTTP_HEADER *AppendList[], OPTIONAL
65 OUT UINTN *NewMessageSize,
66 OUT VOID **NewMessage
67 )
68 {
69 EFI_STATUS Status;
70 EFI_HTTP_HEADER *SeedHeaderFields;
71 UINTN SeedFieldCount;
72 UINTN Index;
73 EFI_HTTP_HEADER *TempHeaderFields;
74 UINTN TempFieldCount;
75 EFI_HTTP_HEADER *NewHeaderFields;
76 UINTN NewFieldCount;
77 EFI_HTTP_HEADER *HttpHeader;
78 UINTN StrLength;
79 UINT8 *NewMessagePtr;
80
81 SeedHeaderFields = NULL;
82 SeedFieldCount = 0;
83 TempHeaderFields = NULL;
84 TempFieldCount = 0;
85 NewHeaderFields = NULL;
86 NewFieldCount = 0;
87
88 HttpHeader = NULL;
89 StrLength = 0;
90 NewMessagePtr = NULL;
91 *NewMessageSize = 0;
92 Status = EFI_SUCCESS;
93
94 if (This == NULL) {
95 return EFI_INVALID_PARAMETER;
96 }
97
98 if (SeedMessage != NULL) {
99 Status = This->Parse (
100 This,
101 SeedMessage,
102 SeedMessageSize,
103 &SeedHeaderFields,
104 &SeedFieldCount
105 );
106 if (EFI_ERROR (Status)) {
107 goto ON_EXIT;
108 }
109 }
110
111 //
112 // Handle DeleteList
113 //
114 if (SeedFieldCount != 0 && DeleteCount != 0) {
115 TempHeaderFields = AllocateZeroPool (SeedFieldCount * sizeof(EFI_HTTP_HEADER));
116 if (TempHeaderFields == NULL) {
117 Status = EFI_OUT_OF_RESOURCES;
118 goto ON_EXIT;
119 }
120
121 for (Index = 0, TempFieldCount = 0; Index < SeedFieldCount; Index++) {
122 //
123 // Check whether each SeedHeaderFields member is in DeleteList
124 //
125 if (IsValidHttpHeader( DeleteList, DeleteCount, SeedHeaderFields[Index].FieldName)) {
126 Status = SetFieldNameAndValue (
127 &TempHeaderFields[TempFieldCount],
128 SeedHeaderFields[Index].FieldName,
129 SeedHeaderFields[Index].FieldValue
130 );
131 if (EFI_ERROR (Status)) {
132 goto ON_EXIT;
133 }
134 TempFieldCount++;
135 }
136 }
137 } else {
138 TempHeaderFields = SeedHeaderFields;
139 TempFieldCount = SeedFieldCount;
140 }
141
142 //
143 // Handle AppendList
144 //
145 NewHeaderFields = AllocateZeroPool ((TempFieldCount + AppendCount) * sizeof (EFI_HTTP_HEADER));
146 if (NewHeaderFields == NULL) {
147 Status = EFI_OUT_OF_RESOURCES;
148 goto ON_EXIT;
149 }
150
151 for (Index = 0; Index < TempFieldCount; Index++) {
152 Status = SetFieldNameAndValue (
153 &NewHeaderFields[Index],
154 TempHeaderFields[Index].FieldName,
155 TempHeaderFields[Index].FieldValue
156 );
157 if (EFI_ERROR (Status)) {
158 goto ON_EXIT;
159 }
160 }
161
162 NewFieldCount = TempFieldCount;
163
164 for (Index = 0; Index < AppendCount; Index++) {
165 HttpHeader = FindHttpHeader (NewHeaderFields, NewFieldCount, AppendList[Index]->FieldName);
166 if (HttpHeader != NULL) {
167 Status = SetFieldNameAndValue (
168 HttpHeader,
169 AppendList[Index]->FieldName,
170 AppendList[Index]->FieldValue
171 );
172 if (EFI_ERROR (Status)) {
173 goto ON_EXIT;
174 }
175 } else {
176 Status = SetFieldNameAndValue (
177 &NewHeaderFields[NewFieldCount],
178 AppendList[Index]->FieldName,
179 AppendList[Index]->FieldValue
180 );
181 if (EFI_ERROR (Status)) {
182 goto ON_EXIT;
183 }
184 NewFieldCount++;
185 }
186 }
187
188 //
189 // Calculate NewMessageSize, then build NewMessage
190 //
191 for (Index = 0; Index < NewFieldCount; Index++) {
192 HttpHeader = &NewHeaderFields[Index];
193
194 StrLength = AsciiStrLen (HttpHeader->FieldName);
195 *NewMessageSize += StrLength;
196
197 StrLength = sizeof(": ") - 1;
198 *NewMessageSize += StrLength;
199
200 StrLength = AsciiStrLen (HttpHeader->FieldValue);
201 *NewMessageSize += StrLength;
202
203 StrLength = sizeof("\r\n") - 1;
204 *NewMessageSize += StrLength;
205 }
206 StrLength = sizeof("\r\n") - 1;
207 *NewMessageSize += StrLength;
208
209 //
210 // Final 0 for end flag
211 //
212 *NewMessageSize += 1;
213
214 *NewMessage = AllocateZeroPool (*NewMessageSize);
215 if (*NewMessage == NULL) {
216 Status = EFI_OUT_OF_RESOURCES;
217 goto ON_EXIT;
218 }
219
220 NewMessagePtr = (UINT8 *)(*NewMessage);
221
222 for (Index = 0; Index < NewFieldCount; Index++) {
223 HttpHeader = &NewHeaderFields[Index];
224
225 StrLength = AsciiStrLen (HttpHeader->FieldName);
226 CopyMem (NewMessagePtr, HttpHeader->FieldName, StrLength);
227 NewMessagePtr += StrLength;
228
229 StrLength = sizeof(": ") - 1;
230 CopyMem (NewMessagePtr, ": ", StrLength);
231 NewMessagePtr += StrLength;
232
233 StrLength = AsciiStrLen (HttpHeader->FieldValue);
234 CopyMem (NewMessagePtr, HttpHeader->FieldValue, StrLength);
235 NewMessagePtr += StrLength;
236
237 StrLength = sizeof("\r\n") - 1;
238 CopyMem (NewMessagePtr, "\r\n", StrLength);
239 NewMessagePtr += StrLength;
240 }
241 StrLength = sizeof("\r\n") - 1;
242 CopyMem (NewMessagePtr, "\r\n", StrLength);
243 NewMessagePtr += StrLength;
244
245 *NewMessagePtr = 0;
246
247 ASSERT (*NewMessageSize == (UINTN)NewMessagePtr - (UINTN)(*NewMessage) + 1);
248
249 //
250 // Free allocated buffer
251 //
252 ON_EXIT:
253 if (SeedHeaderFields != NULL) {
254 FreeHeaderFields(SeedHeaderFields, SeedFieldCount);
255 }
256
257 if (TempHeaderFields != NULL) {
258 FreeHeaderFields(TempHeaderFields, TempFieldCount);
259 }
260
261 if (NewHeaderFields != NULL) {
262 FreeHeaderFields(NewHeaderFields, NewFieldCount);
263 }
264
265 return Status;
266 }
267
268
269 /**
270 Parses HTTP header and produces an array of key/value pairs.
271
272 The Parse() function is used to transform data stored in HttpHeader
273 into a list of fields paired with their corresponding values.
274
275 @param[in] This Pointer to EFI_HTTP_UTILITIES_PROTOCOL instance.
276 @param[in] HttpMessage Contains raw unformatted HTTP header string.
277 @param[in] HttpMessageSize Size of HTTP header.
278 @param[out] HeaderFields Array of key/value header pairs.
279 @param[out] FieldCount Number of headers in HeaderFields.
280
281 @retval EFI_SUCCESS Allocation succeeded.
282 @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been
283 initialized.
284 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
285 This is NULL.
286 HttpMessage is NULL.
287 HeaderFields is NULL.
288 FieldCount is NULL.
289 **/
290 EFI_STATUS
291 EFIAPI
292 HttpUtilitiesParse (
293 IN EFI_HTTP_UTILITIES_PROTOCOL *This,
294 IN CHAR8 *HttpMessage,
295 IN UINTN HttpMessageSize,
296 OUT EFI_HTTP_HEADER **HeaderFields,
297 OUT UINTN *FieldCount
298 )
299 {
300 EFI_STATUS Status;
301 CHAR8 *TempHttpMessage;
302 CHAR8 *Token;
303 CHAR8 *NextToken;
304 CHAR8 *FieldName;
305 CHAR8 *FieldValue;
306 UINTN Index;
307
308 Status = EFI_SUCCESS;
309 TempHttpMessage = NULL;
310 Token = NULL;
311 NextToken = NULL;
312 FieldName = NULL;
313 FieldValue = NULL;
314 Index = 0;
315
316 if (This == NULL || HttpMessage == NULL || HeaderFields == NULL || FieldCount == NULL) {
317 return EFI_INVALID_PARAMETER;
318 }
319
320 TempHttpMessage = AllocateZeroPool (HttpMessageSize);
321 if (TempHttpMessage == NULL) {
322 return EFI_OUT_OF_RESOURCES;
323 }
324
325 CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize);
326
327 //
328 // Get header number
329 //
330 *FieldCount = 0;
331 Token = TempHttpMessage;
332 while (TRUE) {
333 FieldName = NULL;
334 FieldValue = NULL;
335 NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue);
336 Token = NextToken;
337 if (FieldName == NULL || FieldValue == NULL) {
338 break;
339 }
340
341 (*FieldCount)++;
342 }
343
344 if (*FieldCount == 0) {
345 Status = EFI_INVALID_PARAMETER;
346 goto ON_EXIT;
347 }
348
349 //
350 // Allocate buffer for header
351 //
352 *HeaderFields = AllocateZeroPool ((*FieldCount) * sizeof(EFI_HTTP_HEADER));
353 if (*HeaderFields == NULL) {
354 *FieldCount = 0;
355 Status = EFI_OUT_OF_RESOURCES;
356 goto ON_EXIT;
357 }
358
359 CopyMem (TempHttpMessage, HttpMessage, HttpMessageSize);
360
361 //
362 // Set Field and Value to each header
363 //
364 Token = TempHttpMessage;
365 while (Index < *FieldCount) {
366 FieldName = NULL;
367 FieldValue = NULL;
368 NextToken = GetFieldNameAndValue (Token, &FieldName, &FieldValue);
369 Token = NextToken;
370 if (FieldName == NULL || FieldValue == NULL) {
371 break;
372 }
373
374 Status = SetFieldNameAndValue (&(*HeaderFields)[Index], FieldName, FieldValue);
375 if (EFI_ERROR (Status)) {
376 *FieldCount = 0;
377 FreeHeaderFields (*HeaderFields, Index);
378 goto ON_EXIT;
379 }
380
381 Index++;
382 }
383
384 //
385 // Free allocated buffer
386 //
387 ON_EXIT:
388 if (TempHttpMessage != NULL) {
389 FreePool (TempHttpMessage);
390 }
391
392 return Status;
393 }