Jasper Vaneessen 9a5fc674f3
style: Enforce linting rules on markdown files
* chore: add markdownlint-cli2 and config for mkdocs

* style: enforce linting rules on mkdocs md files

* chore: tweaks to markdownlint rules

* style: linting changelog

* style: linting release notes

* style: linting .github md files

* style: further linting of docs

* style: linting readmes

* chore: update linting script entries

* docs: tweak release after rebase

* chore: simplify root md linting config

* chore: extend base config

* chore: implement requested changes

* chore: remove unnecessary exception

* chore: fix comment type

* styling: single config + list spacing

* chore: implement requested changes

* chore: use .cjs files for markdownlint config

* chore: implement requested changes
2022-08-25 11:32:09 +02:00

112 lines
4.9 KiB
Markdown

# Parsing and responding to HTTP requests
```mermaid
flowchart TD
ParsingHttphandler("<br>ParsingHttphandler")
ParsingHttphandler --> ParsingHttphandlerArgs
subgraph ParsingHttphandlerArgs[" "]
RequestParser("<strong>RequestParser</strong><br>BasicRequestParser")
AuthorizingHttpHandler("<strong></strong><br>AuthorizingHttpHandler")
ErrorHandler("<strong>ErrorHandler</strong><br><i>ErrorHandler</i>")
ResponseWriter("<strong>ResponseWriter</strong><br>BasicResponseWriter")
end
```
A `ParsingHttpHandler` handles both the parsing of the input data, and the serializing of the output data.
It follows these 3 steps:
1. Use the `RequestParser` to convert the incoming data into an `Operation`.
2. Send the `Operation` to the `AuthorizingHttpHandler` to receive either a `Representation` if the operation was a success,
or an `Error` in case something went wrong.
* In case of an error the `ErrorHandler` will convert the `Error` into a `ResponseDescription`.
3. Use the `ResponseWriter` to output the `ResponseDescription` as an HTTP response.
## Parsing the request
```mermaid
flowchart TD
RequestParser("<strong>RequestParser</strong><br>BasicRequestParser") --> RequestParserArgs
subgraph RequestParserArgs[" "]
TargetExtractor("<strong>TargetExtractor</strong><br>OriginalUrlExtractor")
PreferenceParser("<strong>PreferenceParser</strong><br>AcceptPreferenceParser")
MetadataParser("<strong>MetadataParser</strong><br><i>MetadataParser</i>")
BodyParser("<br><i>Bodyparser</i>")
Conditions("<br>BasicConditionsParser")
end
OriginalUrlExtractor --> IdentifierStrategy("<strong>IdentifierStrategy</strong><br><i>IdentifierStrategy</i>")
```
The `BasicRequestParser` is mostly an aggregator of multiple smaller parsers that each handle a very specific part.
### URL
This is a single class, the `OriginalUrlExtractor`, but fulfills the very important role
of making sure input URLs are handled consistently.
The query parameters will always be completely removed from the URL.
There is also an algorithm to make sure all URLs have a "canonical" version as for example both `&` and `%26`
can be interpreted in the same way.
Specifically all special characters will be encoded into their percent encoding.
The `IdentifierStrategy` it gets as input is used to determine if the resulting URL is within the scope of the server.
This can differ depending on if the server uses subdomains or not.
The resulting identifier will be stored in the `target` field of an `Operation` object.
### Preferences
The `AcceptPreferenceParser` parses the `Accept` header and all the relevant `Accept-*` headers.
These will all be put into the `preferences` field of an `Operation` object.
These will later be used to handle the content negotiation.
For example, when sending an `Accept: text/turtle; q=0.9` header,
this wil result in the preferences object `{ type: { 'text/turtle': 0.9 } }`.
### Headers
Several other headers can have relevant metadata,
such as the `Content-Type` header,
or the `Link: <http://www.w3.org/ns/ldp#Container>; rel="type"` header
which is used to indicate to the server that a request intends to create a container.
Such headers are converted to RDF triples and stored in the `RepresentationMetadata` object,
which will be part of the `body` field in the `Operation`.
The default `MetadataParser` is a `ParallelHandler` that contains several smaller parsers,
each looking at a specific header.
### Body
In case of most requests, the input data stream is used directly in the `body` field of the `Operation`,
with a few minor checks to make sure the HTTP specification is being followed.
In the case of PATCH requests though,
there are several specific body parsers that will convert the request
into a JavaScript object containing all the necessary information to execute such a PATCH.
Several validation checks will already take place there as well.
### Conditions
The `BasicConditionsParser` parses everything related to conditions headers,
such as `if-none-match` or `if-modified-since`,
and stores the relevant information in the `conditions` field of the `Operation`.
These will later be used to make sure the request should be aborted or not.
## Sending the response
In case a request is successful, the `AuthorizingHttpHandler` will return a `ResponseDescription`,
and if not it will throw an error.
In case an error gets thrown, this will be caught by the `ErrorHandler` and converted into a `ResponseDescription`.
The request preferences will be used to make sure the serialization is one that is preferred.
Either way we will have a `ResponseDescription`,
which will be sent to the `BasicResponseWriter` to convert into output headers, data and a status code.
To convert the metadata into headers, it uses a `MetadataWriter`,
which functions as the reverse of the `MetadataParser` mentioned above:
it has multiple writers which each convert certain metadata into a specific header.