]>
git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpUtilities.c
3 Implementation of help functions to parse HTTP message header.
5 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "HttpDriver.h"
19 Get the next string, which is distinguished by specified seperator.
21 @param[in] String Pointer to the string.
22 @param[in] Seperator Specified seperator used to distinguish where is the beginning
25 @return Pointer to the next string.
26 @return NULL if not find or String is NULL.
30 AsciiStrGetNextToken (
31 IN CONST CHAR8
*String
,
42 if (*Token
== Seperator
) {
43 return (CHAR8
*) (Token
+ 1);
50 Free existing HeaderFields.
52 @param[in] HeaderFields Pointer to array of key/value header pairs waitting for free.
53 @param[in] FieldCount The number of header pairs in HeaderFields.
58 IN EFI_HTTP_HEADER
*HeaderFields
,
64 if (HeaderFields
!= NULL
) {
65 for (Index
= 0; Index
< FieldCount
; Index
++) {
66 if(HeaderFields
[Index
].FieldName
!= NULL
) {
67 FreePool (HeaderFields
[Index
].FieldName
);
69 if(HeaderFields
[Index
].FieldValue
!= NULL
) {
70 FreePool (HeaderFields
[Index
].FieldValue
);
74 FreePool (HeaderFields
);
79 Find required header field in HeaderFields.
81 @param[in] HeaderFields Pointer to array of key/value header pairs.
82 @param[in] FieldCount The number of header pairs.
83 @param[in] FieldName Pointer to header field's name.
85 @return Pointer to the queried header field.
86 @return NULL if not find this required header field.
91 IN EFI_HTTP_HEADER
*HeaderFields
,
98 for (Index
= 0; Index
< FieldCount
; Index
++) {
99 if (AsciiStrCmp (FieldName
, HeaderFields
[Index
].FieldName
) == 0) {
101 // Find the required header field.
103 return &HeaderFields
[Index
];
110 Check whether header field called FieldName is in DeleteList.
112 @param[in] DeleteList Pointer to array of key/value header pairs.
113 @param[in] DeleteCount The number of header pairs.
114 @param[in] FieldName Pointer to header field's name.
116 @return TRUE if FieldName is not in DeleteList, that means this header field is valid.
117 @return FALSE if FieldName is in DeleteList, that means this header field is invalid.
122 IN CHAR8
*DeleteList
[],
123 IN UINTN DeleteCount
,
129 for (Index
= 0; Index
< DeleteCount
; Index
++) {
130 if (AsciiStrCmp (FieldName
, DeleteList
[Index
]) == 0) {
139 Set FieldName and FieldValue into specified HttpHeader.
141 @param[in] HttpHeader Specified HttpHeader.
142 @param[in] FieldName FieldName of this HttpHeader.
143 @param[in] FieldValue FieldValue of this HttpHeader.
146 @retval EFI_SUCCESS The FieldName and FieldValue are set into HttpHeader successfully.
147 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
151 SetFieldNameAndValue (
152 IN EFI_HTTP_HEADER
*HttpHeader
,
158 UINTN FieldValueSize
;
160 if (HttpHeader
->FieldName
!= NULL
) {
161 FreePool (HttpHeader
->FieldName
);
163 if (HttpHeader
->FieldValue
!= NULL
) {
164 FreePool (HttpHeader
->FieldValue
);
167 FieldNameSize
= AsciiStrSize (FieldName
);
168 HttpHeader
->FieldName
= AllocateZeroPool (FieldNameSize
);
169 if (HttpHeader
->FieldName
== NULL
) {
170 return EFI_OUT_OF_RESOURCES
;
172 CopyMem (HttpHeader
->FieldName
, FieldName
, FieldNameSize
);
173 HttpHeader
->FieldName
[FieldNameSize
- 1] = 0;
175 FieldValueSize
= AsciiStrSize (FieldValue
);
176 HttpHeader
->FieldValue
= AllocateZeroPool (FieldValueSize
);
177 if (HttpHeader
->FieldValue
== NULL
) {
178 FreePool (HttpHeader
->FieldName
);
179 return EFI_OUT_OF_RESOURCES
;
181 CopyMem (HttpHeader
->FieldValue
, FieldValue
, FieldValueSize
);
182 HttpHeader
->FieldValue
[FieldValueSize
- 1] = 0;
188 Get one key/value header pair from the raw string.
190 @param[in] String Pointer to the raw string.
191 @param[out] FieldName Pointer to header field's name.
192 @param[out] FieldValue Pointer to header field's value.
194 @return Pointer to the next raw string.
195 @return NULL if no key/value header pair from this raw string.
199 GetFieldNameAndValue (
201 OUT CHAR8
**FieldName
,
202 OUT CHAR8
**FieldValue
206 CHAR8
*FieldValueStr
;
209 if (String
== NULL
|| FieldName
== NULL
|| FieldValue
== NULL
) {
216 FieldValueStr
= NULL
;
220 // Each header field consists of a name followed by a colon (":") and the field value.
222 FieldNameStr
= String
;
223 FieldValueStr
= AsciiStrGetNextToken (FieldNameStr
, ':');
224 if (FieldValueStr
== NULL
) {
228 *(FieldValueStr
- 1) = 0; /// Replace ':' with 0
231 // The field value MAY be preceded by any amount of LWS, though a single SP is preferred.
234 if(*FieldValueStr
== ' ' || *FieldValueStr
== '\t') {
236 } else if (*FieldValueStr
== '\r' && *(FieldValueStr
+ 1) == '\n' &&
237 (*(FieldValueStr
+ 2) == ' ' || *(FieldValueStr
+ 2) == '\t')) {
238 FieldValueStr
= FieldValueStr
+ 3;
245 // Header fields can be extended over multiple lines by preceding each extra
246 // line with at least one SP or HT.
248 StrPtr
= FieldValueStr
;
250 StrPtr
= AsciiStrGetNextToken (StrPtr
, '\r');
251 if (StrPtr
== NULL
|| *StrPtr
!= '\n') {
256 } while (*StrPtr
== ' ' || *StrPtr
== '\t');
259 // Replace '\r' with 0.
264 // Get FieldName and FieldValue.
266 *FieldName
= FieldNameStr
;
267 *FieldValue
= FieldValueStr
;
273 This function is used to manage the headers portion of an HTTP message by providing
274 the ability to add, remove, or replace HTTP headers.
276 @param[in] SeedMessageSize Size in bytes of the initial HTTP header. This can be zero.
277 @param[in] SeedMessage Initial raw unformatted HTTP header to be used as a base for
278 building a new unformatted HTTP header. If NULL, SeedMessageSize
279 is ignored. The buffer containing this message will be allocated
280 and released by the caller.
281 @param[in] DeleteCount Number of null-terminated HTTP header field names in DeleteList.
282 @param[in] DeleteList List of null-terminated HTTP header field names to remove from SeedMessage.
283 Only the field names are in this list because the field values are irrelevant
284 to this operation. If NULL, DeleteCount is ignored. The buffer containing the
285 list will be allocated and released by the caller.
286 @param[in] AppendCount Number of header fields in AppendList.
287 @param[in] AppendList List of HTTP headers to populate NewMessage with. If SeedMessage is not NULL,
288 AppendList will be appended to the existing list from SeedMessage in NewMessage.
289 @param[out] NewMessageSize Pointer to the size in bytes of the new unformatted HTTP header in NewMessage.
290 @param[out] NewMessage Pointer to a new unformatted HTTP header. The storage for this NewMessage is
291 allocated by the driver publishing this protocol, and must be freed by the caller.
293 @retval EFI_SUCCESS Add, remove, and replace operations succeeded.
294 @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
299 IN UINTN SeedMessageSize
,
300 IN VOID
*SeedMessage
, OPTIONAL
301 IN UINTN DeleteCount
,
302 IN CHAR8
*DeleteList
[], OPTIONAL
303 IN UINTN AppendCount
,
304 IN EFI_HTTP_HEADER
*AppendList
[], OPTIONAL
305 OUT UINTN
*NewMessageSize
,
306 OUT VOID
**NewMessage
310 EFI_HTTP_HEADER
*SeedHeaderFields
;
311 UINTN SeedFieldCount
;
313 EFI_HTTP_HEADER
*TempHeaderFields
;
314 UINTN TempFieldCount
;
315 EFI_HTTP_HEADER
*NewHeaderFields
;
317 EFI_HTTP_HEADER
*HttpHeader
;
319 UINT8
*NewMessagePtr
;
321 SeedHeaderFields
= NULL
;
323 TempHeaderFields
= NULL
;
325 NewHeaderFields
= NULL
;
330 NewMessagePtr
= NULL
;
332 Status
= EFI_SUCCESS
;
334 if (SeedMessage
!= NULL
) {
335 Status
= HttpUtilitiesParse (
341 if (EFI_ERROR (Status
)){
349 if(SeedFieldCount
!= 0 && DeleteCount
!= 0) {
350 TempHeaderFields
= AllocateZeroPool (SeedFieldCount
* sizeof(EFI_HTTP_HEADER
));
351 if (TempHeaderFields
== NULL
) {
352 Status
= EFI_OUT_OF_RESOURCES
;
356 for (Index
= 0, TempFieldCount
= 0; Index
< SeedFieldCount
; Index
++) {
358 // Check whether each SeedHeaderFields member is in DeleteList
360 if (IsValidHttpHeader(DeleteList
, DeleteCount
, SeedHeaderFields
[Index
].FieldName
)) {
361 Status
= SetFieldNameAndValue(
362 &TempHeaderFields
[TempFieldCount
],
363 SeedHeaderFields
[Index
].FieldName
,
364 SeedHeaderFields
[Index
].FieldValue
366 if (EFI_ERROR (Status
)){
373 TempHeaderFields
= SeedHeaderFields
;
374 TempFieldCount
= SeedFieldCount
;
380 NewHeaderFields
= AllocateZeroPool ((TempFieldCount
+ AppendCount
) * sizeof(EFI_HTTP_HEADER
));
381 if (NewHeaderFields
== NULL
) {
382 Status
= EFI_OUT_OF_RESOURCES
;
386 for (Index
= 0; Index
< TempFieldCount
; Index
++) {
387 Status
= SetFieldNameAndValue(
388 &NewHeaderFields
[Index
],
389 TempHeaderFields
[Index
].FieldName
,
390 TempHeaderFields
[Index
].FieldValue
392 if (EFI_ERROR (Status
)){
397 NewFieldCount
= TempFieldCount
;
399 for (Index
= 0; Index
< AppendCount
; Index
++) {
400 HttpHeader
= FindHttpHeader(NewHeaderFields
, NewFieldCount
, AppendList
[Index
]->FieldName
);
401 if(HttpHeader
!= NULL
) {
402 Status
= SetFieldNameAndValue(
404 AppendList
[Index
]->FieldName
,
405 AppendList
[Index
]->FieldValue
407 if (EFI_ERROR (Status
)){
411 Status
= SetFieldNameAndValue
412 (&NewHeaderFields
[NewFieldCount
],
413 AppendList
[Index
]->FieldName
,
414 AppendList
[Index
]->FieldValue
416 if (EFI_ERROR (Status
)){
424 // Calculate NewMessageSize, then build NewMessage
426 for (Index
= 0; Index
< NewFieldCount
; Index
++) {
427 HttpHeader
= &NewHeaderFields
[Index
];
429 StrLength
= AsciiStrLen (HttpHeader
->FieldName
);
430 *NewMessageSize
+= StrLength
;
432 StrLength
= sizeof(": ") - 1;
433 *NewMessageSize
+= StrLength
;
435 StrLength
= AsciiStrLen (HttpHeader
->FieldValue
);
436 *NewMessageSize
+= StrLength
;
438 StrLength
= sizeof(HTTP_CRLF_STR
) - 1;
439 *NewMessageSize
+= StrLength
;
441 StrLength
= sizeof(HTTP_CRLF_STR
) - 1;
442 *NewMessageSize
+= StrLength
;
444 // Final 0 for end flag.
446 *NewMessageSize
+= 1;
448 *NewMessage
= AllocateZeroPool (*NewMessageSize
);
449 if (*NewMessage
== NULL
) {
450 Status
= EFI_OUT_OF_RESOURCES
;
454 NewMessagePtr
= (UINT8
*)(*NewMessage
);
456 for (Index
= 0; Index
< NewFieldCount
; Index
++) {
457 HttpHeader
= &NewHeaderFields
[Index
];
459 StrLength
= AsciiStrLen (HttpHeader
->FieldName
);
460 CopyMem (NewMessagePtr
, HttpHeader
->FieldName
, StrLength
);
461 NewMessagePtr
+= StrLength
;
463 StrLength
= sizeof(": ") - 1;
464 CopyMem (NewMessagePtr
, ": ", StrLength
);
465 NewMessagePtr
+= StrLength
;
467 StrLength
= AsciiStrLen (HttpHeader
->FieldValue
);
468 CopyMem (NewMessagePtr
, HttpHeader
->FieldValue
, StrLength
);
469 NewMessagePtr
+= StrLength
;
471 StrLength
= sizeof(HTTP_CRLF_STR
) - 1;
472 CopyMem (NewMessagePtr
, HTTP_CRLF_STR
, StrLength
);
473 NewMessagePtr
+= StrLength
;
475 StrLength
= sizeof(HTTP_CRLF_STR
) - 1;
476 CopyMem (NewMessagePtr
, HTTP_CRLF_STR
, StrLength
);
477 NewMessagePtr
+= StrLength
;
481 ASSERT (*NewMessageSize
== (UINTN
) NewMessagePtr
- (UINTN
) (*NewMessage
) + 1);
484 // Free allocated buffer
487 if(SeedHeaderFields
!= NULL
) {
488 FreeHeaderFields(SeedHeaderFields
, SeedFieldCount
);
491 if(TempHeaderFields
!= NULL
) {
492 FreeHeaderFields(TempHeaderFields
, TempFieldCount
);
495 if(NewHeaderFields
!= NULL
) {
496 FreeHeaderFields(NewHeaderFields
, NewFieldCount
);
503 This function is used to transform data stored in HttpMessage into a list of fields
504 paired with their corresponding values.
506 @param[in] HttpMessage Contains raw unformatted HTTP header string. The buffer for this string will
507 be allocated and released by the caller.
508 @param[in] HttpMessageSize Size in bytes of raw unformatted HTTP header.
509 @param[out] HeaderFields Array of key/value header pairs. The storage for all header pairs is allocated
510 by the driver publishing this protocol, and must be freed by the caller.
511 @param[out] FieldCount Number of headers in HeaderFields.
513 @retval EFI_SUCCESS Parse HTTP header into array of key/value pairs succeeded.
514 @retval EFI_OUT_OF_RESOURCES Could not allocate memory for NewMessage.
515 @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
517 HeaderFields is NULL.
523 IN CHAR8
*HttpMessage
,
524 IN UINTN HttpMessageSize
,
525 OUT EFI_HTTP_HEADER
**HeaderFields
,
526 OUT UINTN
*FieldCount
530 CHAR8
*TempHttpMessage
;
537 if (HttpMessage
== NULL
|| HeaderFields
== NULL
|| FieldCount
== NULL
) {
538 return EFI_INVALID_PARAMETER
;
541 Status
= EFI_SUCCESS
;
542 TempHttpMessage
= NULL
;
550 TempHttpMessage
= AllocateZeroPool (HttpMessageSize
);
551 if (TempHttpMessage
== NULL
) {
552 return EFI_OUT_OF_RESOURCES
;
555 CopyMem (TempHttpMessage
, HttpMessage
, HttpMessageSize
);
560 Token
= TempHttpMessage
;
564 NextToken
= GetFieldNameAndValue (Token
, &FieldName
, &FieldValue
);
566 if (FieldName
== NULL
|| FieldValue
== NULL
) {
573 if(*FieldCount
== 0) {
574 Status
= EFI_INVALID_PARAMETER
;
579 // Allocate buffer for header
581 *HeaderFields
= AllocateZeroPool ((*FieldCount
) * sizeof(EFI_HTTP_HEADER
));
582 if (*HeaderFields
== NULL
) {
584 Status
= EFI_OUT_OF_RESOURCES
;
588 CopyMem (TempHttpMessage
, HttpMessage
, HttpMessageSize
);
591 // Set Field and Value to each header
593 Token
= TempHttpMessage
;
594 while (Index
< *FieldCount
) {
597 NextToken
= GetFieldNameAndValue (Token
, &FieldName
, &FieldValue
);
599 if (FieldName
== NULL
|| FieldValue
== NULL
) {
603 Status
= SetFieldNameAndValue(&(*HeaderFields
)[Index
], FieldName
, FieldValue
);
604 if(EFI_ERROR(Status
)){
606 FreeHeaderFields (*HeaderFields
, Index
);
614 // Free allocated buffer
617 if (TempHttpMessage
!= NULL
) {
618 FreePool(TempHttpMessage
);