Skip to content

Commit 98edb2e

Browse files
authored
aws_http_headers (#161)
1 parent 48ab1ba commit 98edb2e

File tree

7 files changed

+706
-230
lines changed

7 files changed

+706
-230
lines changed

include/aws/http/http.h

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
enum aws_http_errors {
2424
AWS_ERROR_HTTP_UNKNOWN = 0x0800,
25+
AWS_ERROR_HTTP_HEADER_NOT_FOUND,
2526
AWS_ERROR_HTTP_INVALID_HEADER_FIELD,
2627
AWS_ERROR_HTTP_INVALID_HEADER_NAME,
2728
AWS_ERROR_HTTP_INVALID_HEADER_VALUE,

include/aws/http/private/strutil.h

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#ifndef AWS_HTTP_STRUTIL_H
2+
#define AWS_HTTP_STRUTIL_H
3+
14
/*
25
* Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
36
*
@@ -67,3 +70,4 @@ AWS_HTTP_API
6770
struct aws_byte_cursor aws_strutil_trim_http_whitespace(struct aws_byte_cursor cursor);
6871

6972
AWS_EXTERN_C_END
73+
#endif /* AWS_HTTP_STRUTIL_H */

include/aws/http/request_response.h

+170-9
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ struct aws_http_header {
3838
struct aws_byte_cursor value;
3939
};
4040

41+
/**
42+
* A transformable block of HTTP headers.
43+
* Provides a nice API for getting/setting header names and values.
44+
*
45+
* All strings are copied and stored within this datastructure.
46+
* The index of a given header may change any time headers are modified.
47+
* When iterating headers, the following ordering rules apply:
48+
*
49+
* - Headers with the same name will always be in the same order, relative to one another.
50+
* If "A: one" is added before "A: two", then "A: one" will always precede "A: two".
51+
*
52+
* - Headers with different names could be in any order, relative to one another.
53+
* If "A: one" is seen before "B: bee" in one iteration, you might see "B: bee" before "A: one" on the next.
54+
*/
55+
struct aws_http_headers;
56+
4157
/**
4258
* Header block type.
4359
* INFORMATIONAL: Header block for 1xx informational (interim) responses.
@@ -272,22 +288,162 @@ struct aws_http_request_handler_options {
272288

273289
AWS_EXTERN_C_BEGIN
274290

291+
/**
292+
* Return whether both names are equivalent.
293+
* This is a case-insensitive string comparison.
294+
*
295+
* Example Matches:
296+
* "Content-Length" == "content-length" // upper or lower case ok
297+
298+
* Example Mismatches:
299+
* "Content-Length" != " Content-Length" // leading whitespace bad
300+
*/
301+
AWS_HTTP_API
302+
bool aws_http_header_name_eq(struct aws_byte_cursor name_a, struct aws_byte_cursor name_b);
303+
304+
/**
305+
* Create a new headers object.
306+
* The caller has a hold on the object and must call aws_http_headers_release() when they are done with it.
307+
*/
308+
AWS_HTTP_API
309+
struct aws_http_headers *aws_http_headers_new(struct aws_allocator *allocator);
310+
311+
/**
312+
* Acquire a hold on the object, preventing it from being deleted until
313+
* aws_http_headers_release() is called by all those with a hold on it.
314+
*/
315+
AWS_HTTP_API
316+
void aws_http_headers_acquire(struct aws_http_headers *headers);
317+
318+
/**
319+
* Release a hold on the object.
320+
* The object is deleted when all holds on it are released.
321+
*/
322+
AWS_HTTP_API
323+
void aws_http_headers_release(struct aws_http_headers *headers);
324+
325+
/**
326+
* Add a header.
327+
* The underlying strings are copied.
328+
*/
329+
AWS_HTTP_API
330+
int aws_http_headers_add(struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value);
331+
332+
/**
333+
* Add an array of headers.
334+
* The underlying strings are copied.
335+
*/
336+
AWS_HTTP_API
337+
int aws_http_headers_add_array(struct aws_http_headers *headers, const struct aws_http_header *array, size_t count);
338+
339+
/**
340+
* Set a header value.
341+
* The header is added if necessary and any existing values for this name are removed.
342+
* The underlying strings are copied.
343+
*/
344+
AWS_HTTP_API
345+
int aws_http_headers_set(struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value);
346+
347+
/**
348+
* Get the total number of headers.
349+
*/
350+
AWS_HTTP_API
351+
size_t aws_http_headers_count(const struct aws_http_headers *headers);
352+
353+
/**
354+
* Get the header at the specified index.
355+
* The index of a given header may change any time headers are modified.
356+
* When iterating headers, the following ordering rules apply:
357+
*
358+
* - Headers with the same name will always be in the same order, relative to one another.
359+
* If "A: one" is added before "A: two", then "A: one" will always precede "A: two".
360+
*
361+
* - Headers with different names could be in any order, relative to one another.
362+
* If "A: one" is seen before "B: bee" in one iteration, you might see "B: bee" before "A: one" on the next.
363+
*
364+
* AWS_ERROR_INVALID_INDEX is raised if the index is invalid.
365+
*/
366+
AWS_HTTP_API
367+
int aws_http_headers_get_index(
368+
const struct aws_http_headers *headers,
369+
size_t index,
370+
struct aws_http_header *out_header);
371+
372+
/**
373+
* Get the first value for this name, ignoring any additional values.
374+
* AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised if the name is not found.
375+
*/
376+
AWS_HTTP_API
377+
int aws_http_headers_get(
378+
const struct aws_http_headers *headers,
379+
struct aws_byte_cursor name,
380+
struct aws_byte_cursor *out_value);
381+
382+
/**
383+
* Remove all headers with this name.
384+
* AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised if no headers with this name are found.
385+
*/
386+
AWS_HTTP_API
387+
int aws_http_headers_erase(struct aws_http_headers *headers, struct aws_byte_cursor name);
388+
389+
/**
390+
* Remove the first header found with this name and value.
391+
* AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised if no such header is found.
392+
*/
393+
AWS_HTTP_API
394+
int aws_http_headers_erase_value(
395+
struct aws_http_headers *headers,
396+
struct aws_byte_cursor name,
397+
struct aws_byte_cursor value);
398+
399+
/**
400+
* Remove the header at the specified index.
401+
*
402+
* AWS_ERROR_INVALID_INDEX is raised if the index is invalid.
403+
*/
404+
AWS_HTTP_API
405+
int aws_http_headers_erase_index(struct aws_http_headers *headers, size_t index);
406+
407+
/**
408+
* Clear all headers.
409+
*/
410+
AWS_HTTP_API
411+
void aws_http_headers_clear(struct aws_http_headers *headers);
412+
275413
/**
276414
* Create a new request message.
277415
* The message is blank, all properties (method, path, etc) must be set individually.
416+
*
417+
* The caller has a hold on the object and must call aws_http_message_release() when they are done with it.
278418
*/
279419
AWS_HTTP_API
280420
struct aws_http_message *aws_http_message_new_request(struct aws_allocator *allocator);
281421

282422
/**
283423
* Create a new response message.
284424
* The message is blank, all properties (status, headers, etc) must be set individually.
425+
*
426+
* The caller has a hold on the object and must call aws_http_message_release() when they are done with it.
285427
*/
286428
AWS_HTTP_API
287429
struct aws_http_message *aws_http_message_new_response(struct aws_allocator *allocator);
288430

289431
/**
290-
* Destroy the message.
432+
* Acquire a hold on the object, preventing it from being deleted until
433+
* aws_http_message_release() is called by all those with a hold on it.
434+
*/
435+
AWS_HTTP_API
436+
void aws_http_message_acquire(struct aws_http_message *message);
437+
438+
/**
439+
* Release a hold on the object.
440+
* The object is deleted when all holds on it are released.
441+
*/
442+
AWS_HTTP_API
443+
void aws_http_message_release(struct aws_http_message *message);
444+
445+
/**
446+
* Deprecated. This is equivalent to aws_http_message_release().
291447
*/
292448
AWS_HTTP_API
293449
void aws_http_message_destroy(struct aws_http_message *message);
@@ -355,6 +511,19 @@ struct aws_input_stream *aws_http_message_get_body_stream(const struct aws_http_
355511
AWS_HTTP_API
356512
void aws_http_message_set_body_stream(struct aws_http_message *message, struct aws_input_stream *body_stream);
357513

514+
/**
515+
* Get the message's aws_http_headers.
516+
*
517+
* This datastructure has more functions for inspecting and modifying headers than
518+
* are available on the aws_http_message datastructure.
519+
*/
520+
struct aws_http_headers *aws_http_message_get_headers(struct aws_http_message *message);
521+
522+
/**
523+
* Get the message's const aws_http_headers.
524+
*/
525+
const struct aws_http_headers *aws_http_message_get_const_headers(const struct aws_http_message *message);
526+
358527
/**
359528
* Get the number of headers.
360529
*/
@@ -394,14 +563,6 @@ int aws_http_message_add_header_array(
394563
const struct aws_http_header *headers,
395564
size_t num_headers);
396565

397-
/**
398-
* Modify the header at the specified index.
399-
* The message makes its own copy of the underlying strings.
400-
* The previous strings may be destroyed.
401-
*/
402-
AWS_HTTP_API
403-
int aws_http_message_set_header(struct aws_http_message *message, struct aws_http_header header, size_t index);
404-
405566
/**
406567
* Remove the header at the specified index.
407568
* Headers after this index are all shifted back one position.

source/http.c

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ static struct aws_error_info s_errors[] = {
3434
AWS_DEFINE_ERROR_INFO_HTTP(
3535
AWS_ERROR_HTTP_UNKNOWN,
3636
"Encountered an unknown error."),
37+
AWS_DEFINE_ERROR_INFO_HTTP(
38+
AWS_ERROR_HTTP_HEADER_NOT_FOUND,
39+
"The specified header was not found"),
3740
AWS_DEFINE_ERROR_INFO_HTTP(
3841
AWS_ERROR_HTTP_INVALID_HEADER_FIELD,
3942
"Invalid header field, including a forbidden header field."),

0 commit comments

Comments
 (0)