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