• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
HttpUtilitiesBuild(IN EFI_HTTP_UTILITIES_PROTOCOL * This,IN UINTN SeedMessageSize,IN VOID * SeedMessage,OPTIONAL IN UINTN DeleteCount,IN CHAR8 * DeleteList[],OPTIONAL IN UINTN AppendCount,IN EFI_HTTP_HEADER * AppendList[],OPTIONAL OUT UINTN * NewMessageSize,OUT VOID ** NewMessage)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
HttpUtilitiesParse(IN EFI_HTTP_UTILITIES_PROTOCOL * This,IN CHAR8 * HttpMessage,IN UINTN HttpMessageSize,OUT EFI_HTTP_HEADER ** HeaderFields,OUT UINTN * FieldCount)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 }