npm package: @slick_kilmister/tiny-pdf-server
Description: A tiny development server. If you don't already know what it does, you're probably not supposed to be using it.
Author: Kilian Hefti
Latest version: 1.0.7

# Tiny PDF Server

A tiny development server. If you don't already know what it does, you're probably not supposed to be using it.

Install globally with `npm i -g @slick_kilmister/tiny-pdf-server`.

Run `tinypdfserver -h` for information on how to use the cli.

The symbols used in this document are explained in [appendix a](#appendix-a)


## Features


### Requests

The server is able to process the following requests. They are referred to in
this document by the given name.


| name     | request path              | query contains           | response body if successful |
|----------|---------------------------|--------------------------|-----------------------------|
| `!fetch` | `/getDocument`            | `type`, `id`             | `contentfile`               |
| `!match` | `/getDocumentsByProperty` | `key`, &#91;`value`&#93; | xml-list of `batches`       |


#### Respected Request Headers

The set of header fields the server uses is the bare minimum, all other fields are ignored.

- `:path`
- `:method`


### Response Header


#### `!fetch` Request

The response comes with a decent set of headers including useful status codes, mimetype,
size of response body, and last modified date for caching.

| header           | values                                                                          |
|------------------|---------------------------------------------------------------------------------|
| `:status`:       | `200`, `400`, `404`, `405`, `500`                                               |
| `content-type`:  | value given in `//primarycontent/@mimetype` + (if `text/*` "`; charset=utf-8`") |
| `date`           | GMT date+time                                                                   |
| `last-modified`  | `mtime` of content file in GMT format                                           |
| `content length` | size in bytes                                                                   |


#### `!match` Request

The response comes with a limited set of headers

| header          | values                     |
|-----------------|----------------------------|
| `:status`:      | `200`, `400`, `405`, `500` |
| `content-type`: | `application/xml`          |
| `date`          | GMT date+time              |


### Causes for Status Codes

Table of possible status codes and their causes.
-- request path isn't `getDocument`

|  code | name                      | returned when                                                               |
|------:|---------------------------|-----------------------------------------------------------------------------|
| `200` | ok (`!fetch`)             | successfully resolved `type` and `id` query params to a content file        |
| `200` | ok (`!match`)             | successfully resolved `key` and `value` query params to a list of documents |
| `400` | bad request               | request path isn't `getDocument` or `getDocumentsByProperty`                |
| `400` | bad request (`!fetch`)    | query params don't include both `type` and `id`                             |
| `400` | bad request (`!match`)    | query params don't include `key`                                            |
| `404` | file not found (`!fetch`) | could not find a resource xml-file for a given `type`-`id` combo            |
|   --- | file not found (`!match`) | **not possible**, if no match is found, returns an empty element            |
| `405` | method not allowed        | request specified any method besides `GET` (takes precedence over `400`)    |
| `500` | internal server error     | [see server behavior for details](#server-behavior)                         |


## Server Behavior

- Any log entry that coincides with a `500` status code will be logged to `stderr`,
  anything else is logged to `stdout`.
- The server inherently knows wether `stdout` and `stderr` support colors and
  will format its output accordingly.
- The server supports standard redirecting of `stdout` and `stderr`. eg.
  - `tinypdfserver config.json >>out.log 2>>err.log` will
    **append** `stdout` to `out.log` and `stderr` to `err.log`
  - `tinypdfserver config.json >>out.log 2>&1` will
    **append** `stdout` **and** `stderr` to `out.log`
  - `tinypdfserver config.json >out.log 2>err.log` will
    **overwrite** `out.log` with `stdout` and `err.log` with `stderr`


### Core Routine

1. if `:method` is not `GET`
   - break (code: `405`; logs: `<:method>; <code>`)
2. switch on: `:path` starts with
   - case `/getDocument?`
      1. if query doesn't contain `?type` and `?id`
         - switch to default
      2. if no match for `dockey`
         - break (code `404`; logs: `<dockey>; <code>`)
      3. if any of the following:
         - error reading `docfile`
         - `docfile` has unexpected shape
         - `docfile` points to non-existent `contentfile`
         - error reading `contentfile`
      4. then:
         - break (code `500`; logs: error message)
      5. send `contentfile`
         - on success: 
           - break (code: `200`; logs: `<dockey>; <contentfile name>; <code>`)
         - on error: 
           - break (code: `500`; logs: error message)
   - case `/getDocumentsByProperty?`
      1. if query doesn't contain `?name`
         - switch to default
      2. send `doclist start`
      3. repeat with every file in xml-directory
         1. if filename doesn't end with `.xml`
            - continue
         2. if any of the following:
            - error reading `docfile`
            - `docfile` has unexpected shape
         3. then:
            - continue (logs: acknowledgement)
         4. if `batch` matches query parameters
            - send `batch`
      4. send `doclist end`
         - on success:
           - break (code: `200`; logs: `<?name>; <?value>; <# of matches>; <code>`)
         - on error:
           - break (code: `500`; logs: error message)
   - default: `:path` is invalid
      - break (code: 400, logs: `<:path>; <code>`)
3. client prematurely closed connection
   - break (logs acknowledgement)
4. end


## Appendix A

List of symbols used in this document and their meaning

| symbol                   | refers to                                                                        |
|--------------------------|----------------------------------------------------------------------------------|
| `:method` &#124; `:path` | value of http pseudo-header-field value                                          |
| `!<req>`                 | a request of a given type as defined in [request](#requests)                     |
| `?<name>`                | value of the query parameter `<name>`                                            |
| `well-formed <type>`     | a valid piece of data of type `<type>` as described in [appendix b](#appendix-b) |
| `dockey`                 | `?type`/`?id`-pair of a `!fetch` request joined by `_`                           |
| `docfile`                | a data-file used by the server                                                   |
| `batch`                  | the data-structure described by a `well-formed` `docfile`                        |
| `contentfile`            | the file specified in an xml `well-formed` `docfile`                             |
| `code`                   | http status code                                                                 |
| `doclist`                | the xml return by a `!match` request                                             |
| `doclist start`          | xml-declaration and opening tag of topmost element                               |
| `doclist end`            |                                                                                  |


## Appendix B

- The `well-formed` qualifier indicates some piece of data SHOULD NOT result in
  an error when processed by the server. Specific types are described in the
  following table
- The `malformed` qualifier indicates some piece of data WILL result in an
  error when processed by the server. It's definition is implicit as
  anything that doesn't qualify as `well-formed`.

Description of `well-formed` types, denoted by "`well-formed` &lt;type&gt;"

| type      | description                                                                         |
|-----------|-------------------------------------------------------------------------------------|
| request   | any request described in [requests](#requests)                                      |
| `docfile` | an xml document of usable shape as described in [the next section](#document-shape) |


### Document Shape

A `well-formed` `docfile` has the following structure:

- an optional xml-declaration (`<?xml version="1.0" encoding="utf-8" ?>` if absent),
- one `<batch>` element containing
  - one `<document>` element containing
    - any number of `<property>` elements with
      - a `name` attribute
      - an optional `value` attribute (`null` if absent)
    - one `<primarycontent>` element
      - with an optional `mimetype` attribute (`application/pdf` if absent)
      - containing one `<file>` element with a `contentfile` attribute