blob: 69c782b9a156c9f0883329b0132573e40ecbabbc [file] [log] [blame] [raw]
#ifndef H_HTTP_RESPONSE_H
#define H_HTTP_RESPONSE_H
/*
Copyright: Boaz Segev, 2016-2017
License: MIT
Feel free to copy, use and enjoy according to the license provided.
*/
#include "http_request.h"
#include <stdio.h>
#include <time.h>
typedef struct {
/** The protocol version family (HTTP/1.1 / HTTP/2 etc'). */
enum HTTP_VERSION http_version;
/** Will be set to TRUE (1) once the headers were sent. */
unsigned headers_sent : 1;
/** Set to true when the "Date" header is written to the buffer. */
unsigned date_written : 1;
/** Set to true when the "Connection" header is written to the buffer. */
unsigned connection_written : 1;
/** Set to true when the "Content-Length" header is written to the buffer. */
unsigned content_length_written : 1;
/** Set to true in order to close the connection once the response was sent.
*/
unsigned should_close : 1;
/** Internally used by the logging API. */
unsigned logged : 1;
/** Set this value to TRUE to indicate the request pointer should be freed. */
unsigned request_dupped : 1;
/** The response status */
uint16_t status;
/** The socket UUID for the response. */
intptr_t fd;
/** The originating request. */
http_request_s *request;
/** The body's response length.
*
* If this isn't set manually, the first call to `http_response_write_body`
* (and friends) will set the length to the length being written (which might
* be less then the total data sent, if the sending is fragmented).
*
* The value to -1 to prevents `http_response_s` from sending the
* `Content-Length` header.
*/
ssize_t content_length;
/** The HTTP Date for the response (in seconds since epoche).
*
* Defaults to now (approximately, not exactly, uses cached time data).
*
* The date will be automatically formatted to match the HTTP protocol
* specifications.
*
* It is better to avoid setting the "Date" header manualy.
*/
time_t date;
/** The HTTP Last-Modified date for the response (in seconds since epoche).
*
* Defaults to now (approximately, not exactly, uses cached time data).
*
* The date will be automatically formatted to match the HTTP protocol
* specifications.
*
* It is better to avoid setting the "Last-Modified" header manualy.
*/
time_t last_modified;
/**
Internally used by the logging API.
*/
clock_t clock_start;
} http_response_s;
/**
The struct HttpCookie is a helper for seting cookie data.
This struct is used together with the `http_response_set_cookie`. i.e.:
http_response_set_cookie(response,
.name = "my_cookie",
.value = "data" );
*/
typedef struct {
/** The cookie's name (key). */
char *name;
/** The cookie's value (leave blank to delete cookie). */
char *value;
/** The cookie's domain (optional). */
char *domain;
/** The cookie's path (optional). */
char *path;
/** The cookie name's size in bytes or a terminating NULL will be assumed.*/
size_t name_len;
/** The cookie value's size in bytes or a terminating NULL will be assumed.*/
size_t value_len;
/** The cookie domain's size in bytes or a terminating NULL will be assumed.*/
size_t domain_len;
/** The cookie path's size in bytes or a terminating NULL will be assumed.*/
size_t path_len;
/** Max Age (how long should the cookie persist), in seconds (0 == session).*/
int max_age;
/** Limit cookie to secure connections.*/
unsigned secure : 1;
/** Limit cookie to HTTP (intended to prevent javascript access/hijacking).*/
unsigned http_only : 1;
} http_cookie_s;
/* *****************************************************************************
Initialization
***************************************************************************** */
/** Creates / allocates a protocol version's response object. */
http_response_s *http_response_create(http_request_s *request);
/** Destroys the response object. No data is sent.*/
void http_response_destroy(http_response_s *);
/** Sends the data and destroys the response object.*/
void http_response_finish(http_response_s *);
/* *****************************************************************************
Writing data to the response object
***************************************************************************** */
/**
Writes a header to the response. This function writes only the requested
number of bytes from the header name and the requested number of bytes from
the header value. It can be used even when the header name and value don't
contain NULL terminating bytes by passing the `.name_len` or `.value_len` data
in the `http_headers_s` structure.
If the header buffer is full or the headers were already sent (new headers
cannot be sent), the function will return -1.
On success, the function returns 0.
*/
int http_response_write_header_fn(http_response_s *, http_header_s header);
#define http_response_write_header(response, ...) \
http_response_write_header_fn(response, (http_header_s){__VA_ARGS__})
/**
Set / Delete a cookie using this helper function.
To set a cookie, use (in this example, a session cookie):
http_response_set_cookie(response,
.name = "my_cookie",
.value = "data");
To delete a cookie, use:
http_response_set_cookie(response,
.name = "my_cookie",
.value = NULL);
This function writes a cookie header to the response. Only the requested
number of bytes from the cookie value and name are written (if none are
provided, a terminating NULL byte is assumed).
Both the name and the value of the cookie are checked for validity (legal
characters), but other properties aren't reviewed (domain/path) - please make
sure to use only valid data, as HTTP imposes restrictions on these things.
If the header buffer is full or the headers were already sent (new headers
cannot be sent), the function will return -1.
On success, the function returns 0.
*/
int http_response_set_cookie(http_response_s *, http_cookie_s);
#define http_response_set_cookie(response, ...) \
http_response_set_cookie(response, (http_cookie_s){__VA_ARGS__})
/**
Sends the headers (if they weren't previously sent) and writes the data to the
underlying socket.
The body will be copied to the server's outgoing buffer.
If the connection was already closed, the function will return -1. On success,
the function returns 0.
*/
int http_response_write_body(http_response_s *, const char *body,
size_t length);
/**
Sends the headers (if they weren't previously sent) and writes the data to the
underlying socket.
The server's outgoing buffer will take ownership of the file and close it
using `close` once the data was sent.
If the connection was already closed, the function will return -1. On success,
the function returns 0. The file is alsways closed by the function.
If should be possible to destroy the response object and send an error response
if an error is detected. The function will avoid sending any data before it
knows the likelyhood of error is small enough.
*/
int http_response_sendfile(http_response_s *, int source_fd, off_t offset,
size_t length);
/**
Attempts to send the file requested using an **optional** response object (if no
response object is pointed to, a temporary response object will be created).
If a `file_path_unsafe` is provided, it will be appended to the `file_path_safe`
(if any) and URL decoded before attempting to locate and open the file. Any
insecure path manipulations in the `file_path_unsafe` (i.e. `..` or `//`) will
cause the function to fail.
`file_path_unsafe` MUST begine with a `/`, or it will be appended to
`file_path_safe` as part of the last folder's name. if `file_path_safe` ends
with a `/`, it will be trancated.
If the `log` flag is set, response logging will be performed.
If the path ends with a backslash ('/'), the string `"index.html"` will be
appended (a default file name for when serving a folder). No automatic folder
indexing is supported.
This function will honor Ranged requests by setting the byte range
appropriately.
On failure, the function will return -1 (no response will be sent).
On success, the function returns 0.
*/
int http_response_sendfile2(http_response_s *response, http_request_s *request,
const char *file_path_safe, size_t path_safe_len,
const char *file_path_unsafe,
size_t path_unsafe_len, uint8_t log);
/* *****************************************************************************
Helpers and common tasks
***************************************************************************** */
/** Gets a response status, as a string. */
const char *http_response_status_str(uint16_t status);
/** Gets the mime-type string (C string) associated with the file extension. */
const char *http_response_ext2mime(const char *ext);
/** Starts counting miliseconds for log results. */
void http_response_log_start(http_response_s *);
#endif