Skip to content

3. Http entities and it's dependencies in depth

Esteve Autet Alexe edited this page Apr 22, 2024 · 1 revision

Entities

Before spinning up an HTTP server, you need to know how HTTP entities are deserialized in the library.

Base entity

Since HTTP entities have parts in common, an abstract class called BaseEntity exists, which contains the BodyConverter and the HeaderCollection, it also contains other internal methods to parse and deserialize the head. But it's mostly centered in validating and deserializing the body and headers of the entity.

BaseEntity is an abstract class, it can't be instantiated, but it exposes some public properties that are relevant to implementations. This class is not meant to be manually implemented, and in future versions it might be hidden away by being made internal.

Properties:

  • Headers, the headers as a HeaderCollection.
  • Body, the body as a BodyConverter.

Methods:

  • string ToString(), converts the instance to a RFC 2616 compliant string entity.
  • string ToArray(), converts the instance to a RFC 2616 compliant byte array, representing the characters of the compliant string entity.

Operators:

  • explicit operator string(BaseEntity), cast the entity to a string by calling the ToString() method on it and returning its content.

Note that the HTTP version is not abstracted because of how the head is parsed, and it's also semantically better not to abstract it.

Request Entity

This entity extends BaseEntity as previously mentioned, simply adding the corresponding head to it.

As per standard, the head of a request entity is the following GET /path HTTP1.1, this means that we are making a get request to the /path file in whatever server using the HTTP1.1 version of the standard.

Since we have 3 more possible elements to add, these are deserialized into the RequestEntity class.

Properties:

  • RequestMethod, the method of the request, as a RequestMethodType enum.
  • Path, the path of the request as a PartialUri instance.
  • HttpVersion, the HTTP version of the request.
  • SessionParameters, the session parameters, only used in route handlers as a SessionParameterCollection.
  • CapturedGroups, the groups of the regex expression used in the route handler route declaration as a HttpRegexGroupCollection

Constructors:

  • RequestEntity(StreamReader body), builds the entity from a StreamReader whose pointer is at the start of the serialized entity.
  • RequestEntity(RequestMethodType method, PartialUri path, IBody? body = null), initializes a new request entity with the required properties and the version 1.1 of the standard
  • RequestEntity(RequestMethodType method, PartialUri path, string version, IBody? body = null), initializes a new request entity but with the version parameter, to specify a version yourself.

Response Entity

This entity also extends BaseEntity by adding the corresponding response entity head, which would be HTTP1.1 200 OK.

Since this entity is more aimed to construction, the constructors are defined in a better manner.

Properties:

  • HttpVersion, the HTTP version of the request.
  • ResponseCode, the response code as a ResponseCodes enum, it already contains the reason built in.
  • IsSuccessfulResponse, the result of the (int)ResponseCode < 400 expression.

Constructors:

  • ResponseEntity(ResponseCodes responseCode, IBody? body = null), build a response filling the required fields and using the 1.1 version of the standard.
  • ResponseEntity(ResponseCodes, responseCode, string version, IBody? body = null), build a response, filling the required fields and the version manually.
  • ResponseEntity(StreamReader body), build a response with a StreamReader whose pointer points to the start of the body.

Methods:

  • WithHeader(string key, string value), add a header to the response.
  • WithHeaders(Dictionary<string, string> headers), add headers from a dictionary.
  • WithHeaders(HeaderCollection headers), add headers from another HeaderCollection.

Dependencies

While explaining the entities, you might have seen a lot of classes these depend on from, like PartialUri, HeaderCollection... These classes play an important role in the deserialization of entities.

Collections

This library comes with its own collection implementation, which is mostly encapsulations of existing collections in the mscorlib.

ICountable

This interface is extended by all the base collection classes, such as BaseIsolatedMap, BaseMultipleIsolatedMap...

It's designed to promise the following properties.

  • Length, the length of the collection.
  • IsEmpty, most likely the result of Length == 0.

BaseIsolatedMap<TKey, TValue>

This class implements IEnumerable<KeyValuePair<TKey, TValue>> and ICountable, meaning linq is available within classes that extend this one.

This class is abstract, meaning that it can't be instantiated, and it's meant to be publicly implemented if required. It is also an encapsulation of Dictionary<TKey, TValue>, with different property and method structure for the library convenience.

Properties:

  • Length, implemented from ICountable.
  • IsEmpty, implemented from ICountable, definitively the result of the Length == 0 expression.

Methods:

  • bool Contains(TKey key), returns whether the collection has a value mapped to that key.
  • BaseIsolatedMap<TKey, TValue> Set(TKey key, TValue value), add or replace a key to value map in the collection.
  • BaseIsolatedMap<TKey, TValue> Add(BaseIsolatedMap<TKey, TValue> other), add or replace key to value maps from another collection.
  • BaseIsolatedMap<TKey, Tvalue> Add(Dictionary<TKey, TValue> other), add or replace key to value maps from a dictionary.
  • TValue? Get(TKey key), returns the value mapped to that key, or null if no value was mapped to that key.
  • void Remove(TKey key), removes a set from the collection, doesn't return anything.

Operators:

  • TValue? this[TKey key], get a variable mapped to that key or null if none, or set a value mapped to a key, if null remove it.

BaseMultipleIsolatedMap<TKey, TValue>

This class is practically the same as the other one, it also implements IEnumerable<KeyValuePair<TKey, TValue>> and ICountable, the only difference is that instead of encapsulating a dictionary, it encapsulates a List<KeyValuePair<TKey, TValue>> and it internally features a ILookUp<TKey, Tvalue>. This class is also abstract, it can't be instantiated directly.

Properties:

  • Length, the count of all the pairs in the collection.
  • KeyLength, the count of all the keys in the collection, not counting multiple values mapped to a single key.
  • IsEmtpy, the result of Length == 0.

Methods:

  • bool Contains(TKey key), whether a key is present in this collection.
  • BaseMultipleIsolatedMap<TKey, TValue> Add(TKey key, TValue value), add an item to this collection.
  • BaseMultipleIsolatedMap<TKey, TValue> Add(BaseIsolatedMap<TKey, TValue> other), add items to this collection from another collection.
  • BaseMultipleIsolatedMap<TKey, TValue> Add(Dictionary<TKey, TValue> other), add items to this collection from a dictionary.
  • TValue[]? Get(TKey key), get an array with all the values mapped to a key, or null if the key is non-existent.
  • void Remove(TKey key), remove a key and all of its values from the collection, if removing a single value, use linq instead.

Operators:

  • TValue[]? this[TKey key], get an array of values mapped to that key, or add an array of values mapped to that key, or null to remove the key.

MultipleParsingCollection<TKey, TValue>

to be continued...