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