pianod2
multisource multiuser scriptable networked music player
Classes | Macros | Typedefs | Enumerations | Functions | Variables
fb_http.c File Reference

Football HTTP/Websocket functions. More...

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <assert.h>
#include <ctype.h>
#include <sys/stat.h>
#include <time.h>
#include "fb_public.h"
#include "fb_service.h"
#include "sha1.h"
Include dependency graph for fb_http.c:

Classes

struct  media_dictionary_t
 
struct  language_rank
 

Macros

#define _POSIX_C_SOURCE   200112L /* fileno() */
 
#define _BSD_SOURCE   /* strdup(), realpath() */
 
#define _DARWIN_C_SOURCE   /* strdup() on OS X */
 
#define _DEFAULT_SOURCE
 
#define countof(x)   (sizeof (x) / sizeof (*x))
 
#define WEBSOCKET_GUID   "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
 
#define WEBSOCKET_VERSION   "13"
 
#define HTTP_VERSION   "HTTP/1.1"
 
#define get_hex_digit(c)
 

Typedefs

typedef enum ws_opcodes_t OPCODE
 
typedef struct media_dictionary_t MEDIA_DICTIONARY
 
typedef struct language_rank LANGUAGE_RANK
 

Enumerations

enum  ws_opcodes_t {
  WSOC_CONTINUATION = 0x00 , WSOC_TEXT = 0x01 , WSOC_BINARY = 0x02 , WSOC_CLOSE = 0x08 ,
  WSOC_PING = 0x09 , WSOC_PONG = 0x0a , WSOC_MASK = 0x0f
}
 

Functions

static bool fb_queue_http_noflush (FB_CONNECTION *connection, char *message, size_t length)
 
static bool fb_queue_http (FB_CONNECTION *connection, char *message, size_t length)
 
static bool fb_queue_http_alloc (FB_CONNECTION *connection, const char *message, size_t length)
 
static bool write_message (FB_CONNECTION *connection, const char *message)
 
static bool http_header (FB_CONNECTION *connection, const char *message, const char *extra_header, const char *detail)
 
static bool http_response (FB_CONNECTION *connection, const char *message)
 
static bool http_redirect (FB_CONNECTION *connection, const char *location)
 
static void encodeblock (unsigned char *in, unsigned char *out, int len)
 
static void perform_unmask (unsigned char *message, const unsigned long length, const unsigned char *mask)
 
static bool fb_get_http_bytes (FB_CONNECTION *connection, size_t message_size)
 
void reset_ping_interval (FB_CONNECTION *connection)
 Reset the next-ping interval. More...
 
FB_EVENTfb_read_websocket_input (FB_EVENT *event, FB_CONNECTION *connection)
 
bool fb_websocket_ping (FB_CONNECTION *connection)
 
bool fb_websocket_announce_close (FB_CONNECTION *connection)
 
bool fb_websocket_encode (FB_CONNECTION *connection)
 
static bool fb_greet_websocket (FB_CONNECTION *connection)
 
void fb_destroy_httprequest (FB_HTTPREQUEST *request)
 
static bool redirect_to_subdirectory (FB_CONNECTION *connection)
 
static bool url_decode (char *request)
 
void fb_collect_http_request (FB_EVENT *event, FB_HTTPREQUEST *request)
 
static bool store (char **value, const char *newvalue, FB_HTTPREQUEST *request)
 
void fb_collect_http_parameter (char *line, FB_HTTPREQUEST *request)
 
bool fb_http_command (const char *command)
 
static const char * get_media_type (const char *filename)
 
static bool http_serve_data (FB_CONNECTION *connection, char *name, FILE *file, bool sendbody)
 
static bool malicious_request (FB_HTTPREQUEST *request, const char *filename)
 
static bool request_malfunction (FB_CONNECTION *connection, const char *file_path)
 
static char * next_language (char *languages)
 
static int fb_language_compare (const void *elem1, const void *elem2)
 
static LANGUAGE_RANKparse_language_list (int socket, char *languages, int *count)
 
static FILE * http_file_open (FB_CONNECTION *connection, const char *file_name, LANGUAGE_RANK *languages, int language_count, char **file_path)
 
static bool http_file_request (FB_CONNECTION *connection)
 
FB_EVENTfb_execute_http_request (FB_EVENT *event, FB_CONNECTION *connection)
 

Variables

static const unsigned int WS_OPCODE = 0
 
static const unsigned int WS_PAYLOAD = 1
 
static const unsigned int WS_HEADER_MAXIMUM = 32
 
static const unsigned char WS_FIN = 0x80
 
static const unsigned char WS_MASK = 0x80
 
static const unsigned char WS_PAYLOAD_MASK = 0x7f
 
static const unsigned int WS_PAYLOAD_MAX_8BIT = 125
 
static const unsigned int WS_PAYLOAD_MAGIC_16BIT = 126
 
static const unsigned int WS_PAYLOAD_MAGIC_64BIT = 127
 
static const unsigned int WS_PAYLOAD_MAX_16BIT = 0xffff
 
static const char cb64 [] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 

Detailed Description

Football HTTP/Websocket functions.

Macro Definition Documentation

◆ _BSD_SOURCE

#define _BSD_SOURCE   /* strdup(), realpath() */

◆ _DARWIN_C_SOURCE

#define _DARWIN_C_SOURCE   /* strdup() on OS X */

◆ _DEFAULT_SOURCE

#define _DEFAULT_SOURCE

◆ _POSIX_C_SOURCE

#define _POSIX_C_SOURCE   200112L /* fileno() */

◆ countof

#define countof (   x)    (sizeof (x) / sizeof (*x))

◆ get_hex_digit

#define get_hex_digit (   c)
Value:
(((c) >= '0' && (c) <= '9') ? (c) - '0' : \
((c) >= 'a' && (c) <= 'f') ? (c) - '0' + 10 : \
(c) - 'A' + 10)

◆ HTTP_VERSION

#define HTTP_VERSION   "HTTP/1.1"

◆ WEBSOCKET_GUID

#define WEBSOCKET_GUID   "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

◆ WEBSOCKET_VERSION

#define WEBSOCKET_VERSION   "13"

Typedef Documentation

◆ LANGUAGE_RANK

typedef struct language_rank LANGUAGE_RANK

Private structure for language rankings

◆ MEDIA_DICTIONARY

Map file extensions to MIME types reported by HTTP server.

◆ OPCODE

typedef enum ws_opcodes_t OPCODE

Enumeration Type Documentation

◆ ws_opcodes_t

Enumerator
WSOC_CONTINUATION 
WSOC_TEXT 
WSOC_BINARY 
WSOC_CLOSE 
WSOC_PING 
WSOC_PONG 
WSOC_MASK 

Function Documentation

◆ encodeblock()

static void encodeblock ( unsigned char *  in,
unsigned char *  out,
int  len 
)
static
Here is the caller graph for this function:

◆ fb_collect_http_parameter()

void fb_collect_http_parameter ( char *  line,
FB_HTTPREQUEST request 
)

Collect HTTP method parameters that are relevant.

Parameters
linethe HTTP header line received.
requestthe request structure into which details will be stored.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_collect_http_request()

void fb_collect_http_request ( FB_EVENT event,
FB_HTTPREQUEST request 
)

Collect the relevant bits of 'get', 'head' or other HTTP method.

Parameters
eventan event, complete with argv structure.
requestHTTP request structure into which details will be placed.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_destroy_httprequest()

void fb_destroy_httprequest ( FB_HTTPREQUEST request)

Reset a request structure. Frees dynamically allocated elements and clears structure.

Parameters
requestThe request structure to reset.
Here is the caller graph for this function:

◆ fb_execute_http_request()

FB_EVENT* fb_execute_http_request ( FB_EVENT event,
FB_CONNECTION connection 
)

Interpret the collected HTTP request. Return an HTTP error if the request is invalid. If it is a WebSocket request, initiate a WebSocket session. Otherwise serve the request and reset the connection.

Parameters
eventa partially filled event applicable to this connection.
connectionthe connection being served.
Returns
An FB_EVENT_CONNECT event if a WebSocket session is initiated, NULL otherwise.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_get_http_bytes()

static bool fb_get_http_bytes ( FB_CONNECTION connection,
size_t  message_size 
)
static

Ensure that input buffer contains required number of bytes. Read more input if necessary.

Parameters
connectionthe connection read from.
message_sizeThe amount of data we need to collect.
Returns
true when the buffering requirements are met.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_greet_websocket()

static bool fb_greet_websocket ( FB_CONNECTION connection)
static

Respond to the HTTP WebSocket request with the connection upgrade response. This requires crafting a custom SHA1 key to confirm we're really speaking WebSocket.

Parameters
connectionThe connection to greet.
Returns
true on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_http_command()

bool fb_http_command ( const char *  command)

Determine if a request is an HTTP one.

Parameters
commandthe HTTP request (GET, HEAD, etc.)
Returns
true if command is an HTTP request, false otherwise.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_language_compare()

static int fb_language_compare ( const void *  elem1,
const void *  elem2 
)
static

A qsort() etc compliant callback that compares languages for sorting.

Parameters
elem1the first language rank for comparison.
elem2the other language rank for comparison.
Returns
Negative, 0, or positive value in the usual manner.
Here is the caller graph for this function:

◆ fb_queue_http()

static bool fb_queue_http ( FB_CONNECTION connection,
char *  message,
size_t  length 
)
inlinestatic

Add a message to the output queue. The message must be dynamically allocated by caller and is added to the connections queue. On failure. it is freed by this function.

Parameters
connectionthe destination of the message
messagethe message body, dynamically allocated by the caller.
lengththe length of message.
Returns
true on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_queue_http_alloc()

static bool fb_queue_http_alloc ( FB_CONNECTION connection,
const char *  message,
size_t  length 
)
static

Add a message to the output queue, dynamically allocating the message.

Parameters
connectionWhere to send the message.
messageThe message to send.
lengthThe length of message.
Returns
true on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_queue_http_noflush()

static bool fb_queue_http_noflush ( FB_CONNECTION connection,
char *  message,
size_t  length 
)
static

Same as fb_queue_http, but does not flush output after queueing.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_read_websocket_input()

FB_EVENT* fb_read_websocket_input ( FB_EVENT event,
FB_CONNECTION connection 
)

Read data from WebSocket connection. Reads a WebSocket packet and decodes it, and returns an event for the payload.

Parameters
eventa partially filled event applicable to the connection.
connectionthe connection to read from.
Returns
an FB_EVENT_INPUT for the message received, or NULL if the packet is incomplete.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_websocket_announce_close()

bool fb_websocket_announce_close ( FB_CONNECTION connection)

Send a WebSocket close packet. This should be called as last thing prior to closing the connection.

Parameters
connectionThe connection to write the close to.
Returns
true on success, false on failure.
Here is the caller graph for this function:

◆ fb_websocket_encode()

bool fb_websocket_encode ( FB_CONNECTION connection)

Build WebSocket packets from output. Checks if there's a complete packet (line) in the assembly queue. When there is, assemble a WebSocket packet and put it in the output queue.

Parameters
connectionThe connection to check.
Returns
true on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fb_websocket_ping()

bool fb_websocket_ping ( FB_CONNECTION connection)

Send a WebSocket ping packet. Some browsers have timeouts, so we need to send pings as keep-alives.

Parameters
connectionThe connection to check.
Returns
true on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_media_type()

static const char* get_media_type ( const char *  filename)
static

Guess the media type from a file's extension.

Parameters
filenamethe name of a file.
Returns
a media type string corresponding to the file's extension, or the default "text/plain".
Here is the call graph for this function:
Here is the caller graph for this function:

◆ http_file_open()

static FILE* http_file_open ( FB_CONNECTION connection,
const char *  file_name,
LANGUAGE_RANK languages,
int  language_count,
char **  file_path 
)
static

Handle opening a file, accounting for preferred language.

Parameters
connectionThe connection and request for which file is being opened.
file_nameThe name of the file to open, before language mangling.
languagesThe list of languages from Accept-Language header.
language_countThe number of languages in the list.
file_pathThe name of the file that was opened. It is the caller's responsibility to free this, regardless of whether http_file_open succeeded.
Here is the caller graph for this function:

◆ http_file_request()

static bool http_file_request ( FB_CONNECTION connection)
static

Handle a GET or HEAD request. Generate appropriate HTTP error messages if the file is inaccessible or does not exist.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ http_header()

static bool http_header ( FB_CONNECTION connection,
const char *  message,
const char *  extra_header,
const char *  detail 
)
static

Send an HTTP response header to a client. Closes the connection if anything goes wrong.

Parameters
connectionWhere to send the header.
messageThe HTTP response code/text.
extra_headerExtra line(s) to include with the header, or NULL.
detailText to provide to the user, or NULL to go with the default.
Returns
true on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ http_redirect()

static bool http_redirect ( FB_CONNECTION connection,
const char *  location 
)
static

Create a properly formatted HTTP redirect response.

Parameters
connectionWhere to send the response.
locationThe URL to redirect to.
Returns
True on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ http_response()

static bool http_response ( FB_CONNECTION connection,
const char *  message 
)
static

Create a properly formatted HTTP response header.

Parameters
connectionWhere to send the response.
messageThe HTTP response code/text.
Returns
True on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ http_serve_data()

static bool http_serve_data ( FB_CONNECTION connection,
char *  name,
FILE *  file,
bool  sendbody 
)
static

Handle a complete and valid GET or HEAD request.

Parameters
connectionthe connection issuing the request.
namethe name of the file being served.
filean open file handle for the file being served.
sendbodytrue if the file should be served (GET request), false if not (HEAD)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ malicious_request()

static bool malicious_request ( FB_HTTPREQUEST request,
const char *  filename 
)
static

Determine request maliciousness. Requests for a language with a '.' or '/' characters are malicious. Assess the filename of a GET/HEAD request to see if it looks maliciously crafted. Currently, disallow hidden files or parent directories.

Parameters
requestthe request details
filenamethe requested pathname.
Returns
true if the request appears malicious.
Here is the caller graph for this function:

◆ next_language()

static char* next_language ( char *  languages)
static
Here is the caller graph for this function:

◆ parse_language_list()

static LANGUAGE_RANK* parse_language_list ( int  socket,
char *  languages,
int *  count 
)
static

Parse an Accept-Language header into a list of languages.

Parameters
socketThe connection's socket, to which error messages are sent.
languagesThe Accept-Language header value. Modified by this function.
countSet to the number of languages found on return.
Returns
Pointer to array of LANGUAGE_RANKs, or NULL on error.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ perform_unmask()

static void perform_unmask ( unsigned char *  message,
const unsigned long  length,
const unsigned char *  mask 
)
static

Mask or umask a websocket packet.

Parameters
messagethe message to be masked/unmasked.
lengththe length of the message.
maskPointer to a 4 bytes containing mask .
Here is the caller graph for this function:

◆ redirect_to_subdirectory()

static bool redirect_to_subdirectory ( FB_CONNECTION connection)
static

Redirect to a subdirectory. Given a request pointing to a directory (without trailing slash), request the contents (with slash).

Parameters
connectionThe client to redirect.
Returns
True on success, false on failure.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ request_malfunction()

static bool request_malfunction ( FB_CONNECTION connection,
const char *  file_path 
)
static

Determine if request path is valid on the server side.

  • Ensure that the served file is within the served area. We check earlier for malicious requests; this is for erroneous or abusive configuration where a symlink redirects outsite the serve directory.
    Parameters
    connectionthe connection issuing the request
    file_paththe requested pathname.
    Returns
    true if the request is invalid for some reason.
Here is the caller graph for this function:

◆ reset_ping_interval()

void reset_ping_interval ( FB_CONNECTION connection)

Reset the next-ping interval.

Here is the caller graph for this function:

◆ store()

static bool store ( char **  value,
const char *  newvalue,
FB_HTTPREQUEST request 
)
static

Store a value in the request structure, or consider it an error if it's duplicate.

Parameters
valueThe destination of the value.
newvalueThe value store.
requestThe request structure.
Returns
True on success, false on failure.
Here is the caller graph for this function:

◆ url_decode()

static bool url_decode ( char *  request)
static

Decode URL encoding.

Parameters
requestthe URL to decode. Contents are overwritten with decoded URL.
Returns
true if the URL decodes okay, false if it is encoded incorrectly.
Here is the caller graph for this function:

◆ write_message()

static bool write_message ( FB_CONNECTION connection,
const char *  message 
)
static

Send some raw text to a connection.

Parameters
connectionWhere to send the message.
messageThe message to send.
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ cb64

const char cb64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
static

◆ WS_FIN

const unsigned char WS_FIN = 0x80
static

◆ WS_HEADER_MAXIMUM

const unsigned int WS_HEADER_MAXIMUM = 32
static

◆ WS_MASK

const unsigned char WS_MASK = 0x80
static

◆ WS_OPCODE

const unsigned int WS_OPCODE = 0
static

◆ WS_PAYLOAD

const unsigned int WS_PAYLOAD = 1
static

◆ WS_PAYLOAD_MAGIC_16BIT

const unsigned int WS_PAYLOAD_MAGIC_16BIT = 126
static

◆ WS_PAYLOAD_MAGIC_64BIT

const unsigned int WS_PAYLOAD_MAGIC_64BIT = 127
static

◆ WS_PAYLOAD_MASK

const unsigned char WS_PAYLOAD_MASK = 0x7f
static

◆ WS_PAYLOAD_MAX_16BIT

const unsigned int WS_PAYLOAD_MAX_16BIT = 0xffff
static

◆ WS_PAYLOAD_MAX_8BIT

const unsigned int WS_PAYLOAD_MAX_8BIT = 125
static