blob: ae6d8dc53506e0583516158c459909996b24bd75 [file] [log] [blame] [raw]
/*
Copyright: Boaz segev, 2016-2017
License: MIT
Feel free to copy, use and enjoy according to the license provided.
*/
#ifndef HTTP_REQUEST_H
#define HTTP_REQUEST_H
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#ifndef __unused
#define __unused __attribute__((unused))
#endif
typedef struct {
const char *name;
const char *value;
uint16_t name_length;
uint16_t value_length;
} http_headers_s;
typedef struct {
/** points to the HTTP method name. */
const char *method;
/** The portion of the request URL that comes before the '?', if any. */
const char *path;
/** The string length of the path (editing the path requires update). */
/** The portion of the request URL that follows the ?, if any. */
const char *query;
/** Points to a version string. */
const char *version;
/** Points to the body's host header value (a required header). */
const char *host;
/** points to the body's content type header, if any. */
const char *content_type;
/** points to the Upgrade header, if any. */
const char *upgrade;
/** points to the Connection header, if any. */
const char *connection;
/** the body's content's length, in bytes (can be 0). */
size_t content_length;
/* string lengths */
uint16_t method_len;
uint16_t path_len;
uint16_t query_len;
uint16_t host_len;
uint16_t content_type_len;
uint16_t upgrade_len;
/** `version_len` is signed, to allow negative values (SPDY/HTTP2 etc). */
int16_t version_len;
/**
Points the body of the request, if the body exists and is stored in memory.
Otherwise, NULL. */
const char *body_str;
/** points a tmpfile file descriptor containing the body of the request. */
int body_file;
/** semi-private information. */
struct {
/**
When pooling request objects, this points to the next object.
In other times it may contain arbitrary data that can be used by the parser
or implementation.
*/
void *next;
/**
Implementation specific. This, conceptually, holds information about the
"owner" of this request. */
void *owner;
/**
Implementation specific. This, conceptually, holds the connection that
"owns" this request, or an implementation identifier. */
intptr_t fd;
/** the current header position, for API or parser states. */
uint16_t headers_pos;
/** the maximum number of header space availble. */
uint16_t max_headers;
} metadata;
uint16_t connection_len;
uint16_t headers_count;
http_headers_s headers[];
} http_request_s;
__unused static inline void http_request_clear(http_request_s *request) {
if (request->body_file > 0) /* assumes no tempfile with fd 0 */
close(request->body_file);
*request = (http_request_s){
.metadata.owner = request->metadata.owner,
.metadata.fd = request->metadata.fd,
.metadata.max_headers = request->metadata.max_headers,
};
}
/** searches for a header in the header array, both reaturnning it's value and
* setting it's position in the `request->metadata.header_pos` variable.*/
__unused static inline const char *
http_request_find_header(http_request_s *request, const char *header,
size_t header_len) {
if (header == NULL || request == NULL)
return NULL;
if (header_len == 0)
header_len = strlen(header);
request->metadata.headers_pos = 0;
while (request->metadata.headers_pos < request->headers_count) {
if (header_len ==
request->headers[request->metadata.headers_pos].name_length &&
strncasecmp(request->headers[request->metadata.headers_pos].name,
header, header_len) == 0)
return request->headers[request->metadata.headers_pos].value;
request->metadata.headers_pos += 1;
}
return NULL;
}
#define HTTP_REQUEST_SIZE(header_count) \
(sizeof(http_request_s) + ((header_count) * sizeof(http_headers_s)))
#endif