-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathhttpd.h
More file actions
194 lines (166 loc) · 5.1 KB
/
httpd.h
File metadata and controls
194 lines (166 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/**
* @file httpd.h
* @brief Simple HTTP server API for Unix/Linux systems
*
* This header provides a minimal HTTP server implementation with fork-based
* concurrency. Includes routing macros and request/response utilities.
*/
#ifndef _HTTPD_H___
#define _HTTPD_H___
#include <stdio.h>
#include <string.h>
/** @brief HTTP request method (e.g., "GET", "POST") */
extern char *method;
/** @brief Request URI path before query string (e.g., "/index.html") */
extern char *uri;
/** @brief Query string after '?' (e.g., "a=1&b=2") */
extern char *qs;
/** @brief HTTP protocol version (e.g., "HTTP/1.1") */
extern char *prot;
/** @brief POST request payload data */
extern char *payload;
/** @brief Size of POST payload in bytes */
extern int payload_size;
/**
* @brief Start the HTTP server and listen for connections
*
* This function initializes the server, binds to the specified port,
* and enters an infinite loop accepting and handling client connections.
* Each connection is handled in a separate forked process.
*
* @param PORT Port number as a string (e.g., "8000")
* @note This function never returns unless there's a fatal error
* @warning Blocks indefinitely - use Ctrl+C or signals to stop
*/
void serve_forever(const char *PORT);
/**
* @brief Get the value of a specific HTTP request header
*
* @param name Header name (case-sensitive, e.g., "User-Agent")
* @return Pointer to header value string, or NULL if not found
* @note The returned pointer is valid only for the current request
*/
char *request_header(const char *name);
/**
* @brief Structure representing an HTTP header name-value pair
*/
typedef struct {
char *name; /**< Header name */
char *value; /**< Header value */
} header_t;
/** @brief Array storing parsed request headers (max 17 headers) */
extern header_t reqhdr[17];
/**
* @brief Get all HTTP request headers as an array
*
* @return Pointer to array of header_t structures
* @note Array is terminated with a header where name is NULL
* @note Valid only for the current request
*/
header_t *request_headers(void);
/**
* @brief User-defined routing function
*
* This function must be implemented by the user to define request handling.
* Use ROUTE_START(), GET(), POST(), and ROUTE_END() macros to define routes.
*
* @note Called once per request in the forked child process
* @see ROUTE_START, GET, POST, ROUTE_END
*/
void route();
/* ==================== Response Macros ==================== */
/** @brief HTTP protocol version string */
#define RESPONSE_PROTOCOL "HTTP/1.1"
/** @brief Send HTTP 200 OK response header */
#define HTTP_200 printf("%s 200 OK\n\n", RESPONSE_PROTOCOL)
/** @brief Send HTTP 201 Created response header */
#define HTTP_201 printf("%s 201 Created\n\n", RESPONSE_PROTOCOL)
/** @brief Send HTTP 404 Not Found response header */
#define HTTP_404 printf("%s 404 Not found\n\n", RESPONSE_PROTOCOL)
/** @brief Send HTTP 500 Internal Server Error response header */
#define HTTP_500 printf("%s 500 Internal Server Error\n\n", RESPONSE_PROTOCOL)
/* ==================== Routing Macros ==================== */
/**
* @brief Begin route definitions
*
* Must be the first statement in the route() function.
* Use with GET(), POST(), and ROUTE_END() macros.
*
* @code
* void route() {
* ROUTE_START()
* GET("/hello") {
* HTTP_200;
* printf("Hello World");
* }
* ROUTE_END()
* }
* @endcode
*/
#define ROUTE_START() if (0) {
/**
* @brief Define a route for a specific HTTP method and URI
*
* @param METHOD HTTP method string (e.g., "GET", "POST")
* @param URI URI path to match (e.g., "/hello")
*/
#define ROUTE(METHOD, URI) \
} \
else if (strcmp(URI, uri) == 0 && strcmp(METHOD, method) == 0) {
/**
* @brief Define a GET route
*
* @param URI URI path to match (e.g., "/users")
*
* @code
* GET("/users") {
* HTTP_200;
* printf("User list");
* }
* @endcode
*/
#define GET(URI) ROUTE("GET", URI)
/**
* @brief Define a POST route
*
* @param URI URI path to match (e.g., "/users")
*
* @code
* POST("/users") {
* HTTP_201;
* printf("User created: %s", payload);
* }
* @endcode
*/
#define POST(URI) ROUTE("POST", URI)
/**
* @brief Define a HEAD route
*
* HEAD method is identical to GET except the server does not return
* the message body in the response. Useful for checking if a resource
* exists or getting metadata without downloading the full content.
*
* @param URI URI path to match (e.g., "/file.txt")
*
* @code
* HEAD("/file.txt") {
* if (file_exists("public/file.txt")) {
* HTTP_200;
* // Headers sent, no body
* } else {
* HTTP_404;
* }
* }
* @endcode
*/
#define HEAD(URI) ROUTE("HEAD", URI)
/**
* @brief End route definitions
*
* Must be the last statement in the route() function.
* If no routes match, sends HTTP 500 error.
*/
#define ROUTE_END() \
} \
else HTTP_500;
#endif