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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
|
/*
* Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
* All rights reserved
*
* "THE BEER-WARE LICENSE" (Revision 42):
* Sergey Lyubka wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
*/
#ifndef DEFS_HEADER_DEFINED
#define DEFS_HEADER_DEFINED
#include "std_includes.h"
#include "llist.h"
#include "io.h"
#include "shttpd.h"
#include "md5.h"
#define VERSION "1.37" /* Version */
#ifndef CONFIG
#define CONFIG "shttpd.conf" /* Configuration file */
#endif /* CONFIG */
#define HTPASSWD ".htpasswd" /* Passwords file name */
#define DFLT_IO_SIZ "16384" /* Default max request size */
#define HTTP_PORT "80" /* Default listening port */
#define INDEX_FILES "index.html index.htm index.php index.cgi"
#define CGI_EXT ".cgi .pl .php" /* Default CGI extensions */
#define REALM "mydomain.com" /* Default authentication realm */
#define DELIM_CHARS " ," /* Separators for lists */
#define EXPIRE_TIME 3600 /* Expiration time, seconds */
#define ENV_MAX 4096 /* Size of environment block */
#define CGI_ENV_VARS 64 /* Maximum vars passed to CGI */
#define URI_MAX 32768 /* Maximum URI size */
#define MIN_REQ_LEN 16 /* "GET / HTTP/1.1\n\n" */
#define NELEMS(ar) (sizeof(ar) / sizeof(ar[0]))
#ifdef _DEBUG
#define DBG(x) do { printf x ; putchar('\n'); fflush(stdout); } while (0)
#else
#define DBG(x)
#endif /* DEBUG */
#ifdef EMBEDDED
#include "shttpd.h"
#endif /* EMBEDDED */
/*
* Darwin prior to 7.0 and Win32 do not have socklen_t
*/
#ifdef NO_SOCKLEN_T
typedef int socklen_t;
#endif /* NO_SOCKLEN_T */
/*
* For parsing. This guy represents a substring.
*/
struct vec {
const char *ptr;
int len;
};
enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
enum {HDR_DATE, HDR_INT, HDR_STRING}; /* HTTP header types */
enum {E_FATAL = 1, E_LOG = 2}; /* Flags for elog() function */
typedef unsigned long big_int_t; /* Type for Content-Length */
/*
* Unified socket address
*/
struct usa {
socklen_t len;
union {
struct sockaddr sa;
struct sockaddr_in sin;
} u;
};
/*
* This thing is aimed to hold values of any type.
* Used to store parsed headers' values.
*/
union variant {
char *v_str;
int v_int;
big_int_t v_big_int;
time_t v_time;
void (*v_func)(void);
void *v_void;
struct vec v_vec;
};
/*
* This structure is used to hold mime types and associated file extensions.
*/
struct mime_type {
const char *ext;
int ext_len;
const char *mime;
};
struct mime_type_link {
struct llhead link;
char *ext;
int ext_len;
char *mime;
};
/*
* This is used only in embedded configuration. This structure holds a
* registered URI, associated callback function with callback data.
* For non-embedded compilation shttpd_callback_t is not defined, so
* we use union variant to keep the compiler silent.
*/
struct registered_uri {
struct llhead link;
const char *uri;
union variant callback;
void *callback_data;
};
/*
* User may bind a passwords file to any URI. This makes that URI password
* protected: anybody who accesses that URI will be asked to authorize.
*/
struct uri_auth {
struct llhead link;
const char *uri;
const char *file_name;
size_t uri_len;
};
/*
* User may want to handle certain errors. This structure holds the
* handlers for corresponding error codes.
*/
struct error_handler {
struct llhead link;
int code;
union variant callback;
void *callback_data;
};
struct http_header {
int len; /* Header name length */
int type; /* Header type */
size_t offset; /* Value placeholder */
const char *name; /* Header name */
};
/*
* This guy holds parsed HTTP headers
*/
struct headers {
union variant cl; /* Content-Length: */
union variant ct; /* Content-Type: */
union variant connection; /* Connection: */
union variant ims; /* If-Modified-Since: */
union variant user; /* Remote user name */
union variant auth; /* Authorization */
union variant useragent; /* User-Agent: */
union variant referer; /* Referer: */
union variant cookie; /* Cookie: */
union variant location; /* Location: */
union variant range; /* Range: */
union variant status; /* Status: */
union variant transenc; /* Transfer-Encoding: */
};
/* Must go after union variant definition */
#include "ssl.h"
/*
* The communication channel
*/
union channel {
int fd; /* Regular static file */
int sock; /* Connected socket */
struct {
int sock; /* XXX important. must be first */
SSL *ssl; /* shttpd_poll() assumes that */
} ssl; /* SSL-ed socket */
struct {
DIR *dirp;
char *path;
} dir; /* Opened directory */
struct {
void *state; /* For keeping state */
union variant func; /* User callback function */
void *data; /* User defined parameters */
} emb; /* Embedded, user callback */
};
struct stream;
/*
* IO class descriptor (file, directory, socket, SSL, CGI, etc)
* These classes are defined in io_*.c files.
*/
struct io_class {
const char *name;
int (*read)(struct stream *, void *buf, size_t len);
int (*write)(struct stream *, const void *buf, size_t len);
void (*close)(struct stream *);
};
/*
* Data exchange stream. It is backed by some communication channel:
* opened file, socket, etc. The 'read' and 'write' methods are
* determined by a communication channel.
*/
struct stream {
struct conn *conn;
union channel chan; /* Descriptor */
struct io io; /* IO buffer */
const struct io_class *io_class; /* IO class */
int nread_last; /* Bytes last read */
int headers_len;
big_int_t content_len;
unsigned int flags;
#define FLAG_HEADERS_PARSED 1
#define FLAG_SSL_ACCEPTED 2
#define FLAG_R 4 /* Can read in general */
#define FLAG_W 8 /* Can write in general */
#define FLAG_CLOSED 16
#define FLAG_DONT_CLOSE 32
#define FLAG_ALWAYS_READY 64 /* File, dir, user_func */
};
struct conn {
struct llhead link; /* Connections chain */
struct shttpd_ctx *ctx; /* Context this conn belongs to */
struct usa sa; /* Remote socket address */
time_t birth_time; /* Creation time */
time_t expire_time; /* Expiration time */
int status; /* Reply status code */
int method; /* Request method */
char *uri; /* Decoded URI */
unsigned long major_version; /* Major HTTP version number */
unsigned long minor_version; /* Minor HTTP version number */
char *request; /* Request line */
char *headers; /* Request headers */
char *query; /* QUERY_STRING part of the URI */
char *path_info; /* PATH_INFO thing */
const char *mime_type; /* Mime type */
struct headers ch; /* Parsed client headers */
struct stream loc; /* Local stream */
struct stream rem; /* Remote stream */
};
/*
* SHTTPD context
*/
struct shttpd_ctx {
time_t start_time; /* Start time */
int nactive; /* # of connections now */
unsigned long nrequests; /* Requests made */
uint64_t in, out; /* IN/OUT traffic counters */
#if !defined(NO_SSL)
SSL_CTX *ssl_ctx; /* SSL context */
#endif /* NO_SSL */
struct llhead connections; /* List of connections */
struct llhead mime_types; /* Known mime types */
struct llhead registered_uris;/* User urls */
struct llhead uri_auths; /* User auth files */
struct llhead error_handlers; /* Embedded error handlers */
FILE *access_log; /* Access log stream */
FILE *error_log; /* Error log stream */
char *put_auth_file; /* PUT auth file */
char *document_root; /* Document root */
char *index_files; /* Index files */
char *aliases; /* Aliases */
char *mime_file; /* Mime types file */
#if !defined(NO_CGI)
char *cgi_vars; /* CGI environment variables */
char *cgi_extensions; /* CGI extensions */
char *cgi_interpreter; /* CGI script interpreter */
#endif /* NO_CGI */
char *auth_realm; /* Auth realm */
char *global_passwd_file; /* Global passwords file */
char *uid; /* Run as user */
int port; /* Listening port */
int dirlist; /* Directory listing */
int gui; /* Show GUI flag */
int auto_start; /* Start on OS boot */
int io_buf_size; /* IO buffer size */
int inetd_mode; /* Inetd flag */
#if defined(_WIN32)
CRITICAL_SECTION mutex; /* For MT case */
HANDLE ev[2]; /* For thread synchronization */
#elif defined(__rtems__)
rtems_id mutex;
#endif /* _WIN32 */
};
struct listener {
struct llhead link;
struct shttpd_ctx *ctx; /* Context that socket belongs */
int sock; /* Listening socket */
};
/* Option setter function */
typedef void (*optset_t)(struct shttpd_ctx *, void *ptr, const char *string);
struct opt {
int sw; /* Command line switch */
const char *name; /* Option name in config file */
const char *desc; /* Description */
optset_t setter; /* Option setter function */
size_t ofs; /* Value offset in context */
const char *arg; /* Argument format */
const char *def; /* Default option value */
unsigned int flags; /* Flags */
#define OPT_BOOL 1
#define OPT_INT 2
#define OPT_FILE 4
#define OPT_DIR 8
#define OPT_ADVANCED 16
};
extern const struct opt options[];
/*
* In SHTTPD, list of values are represented as comma or space separated
* string. For example, list of CGI extensions can be represented as
* ".cgi,.php,.pl", or ".cgi .php .pl". The macro that follows allows to
* loop through the individual values in that list.
* A "const char *" pointer and size_t variable must be passed to the macro.
* Spaces or commas can be used as delimiters (macro DELIM_CHARS)
*/
#define FOR_EACH_WORD_IN_LIST(s,len) \
for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0; s += len + 1)
/*
* shttpd.c
*/
extern time_t current_time; /* Current UTC time */
extern int tz_offset; /* Offset from GMT time zone */
extern const struct vec known_http_methods[];
extern void stop_stream(struct stream *stream);
extern void decode_url_encoded_string(const char *, int, char *dst, int);
extern void send_server_error(struct conn *, int code, const char *reason);
extern int get_headers_len(const char *buf, size_t buflen);
extern void parse_headers(const char *s, int len, struct headers *parsed);
/*
* mime_type.c
*/
extern const char *get_mime_type(struct shttpd_ctx *, const char *uri, int len);
extern void set_mime_types(struct shttpd_ctx *ctx, const char *path);
/*
* config.c
*/
extern void usage(const char *prog);
extern struct shttpd_ctx *init_from_argc_argv(const char *, int, char *[]);
/*
* log.c
*/
extern void elog(int flags, struct conn *c, const char *fmt, ...);
extern void log_access(FILE *fp, const struct conn *c);
/*
* string.c
*/
#ifndef HAVE_STRLCPY
extern void my_strlcpy(register char *, register const char *, size_t);
#else
#include <string.h>
#define my_strlcpy(d,s,l) strlcpy(d,s,l)
#endif
#ifndef HAVE_STRNCASECMP
extern int my_strncasecmp(register const char *,
register const char *, size_t);
#else
#ifdef __rtems__
/* strncasecmp should be in strings.h, but newlib has it in <string.h> */
#include <string.h>
#else
#include <strings.h>
#endif
#define my_strncasecmp(s1,s2,l) strncasecmp(s1,s2,l)
#endif
#ifndef HAVE_STRNDUP
extern char *my_strndup(const char *ptr, size_t len);
#else
#include <string.h>
#define my_strndup(x,l) strndup((x),(l))
#endif
#ifndef HAVE_STRDUP
extern char *my_strdup(const char *str);
#else
#include <string.h>
#define my_strdup(x) strdup(x)
#endif
extern int my_snprintf(char *buf, size_t buflen, const char *fmt, ...);
/*
* compat_*.c
*/
extern void set_close_on_exec(int fd);
extern int set_non_blocking_mode(int fd);
#if __rtems__
#define my_stat stat
#define my_open open
#define my_remove remove
#define my_rename rename
#define my_mkdir mkdir
#define my_getcwd getcwd
#else
extern int my_stat(const char *, struct stat *stp);
extern int my_open(const char *, int flags, int mode);
extern int my_remove(const char *);
extern int my_rename(const char *, const char *);
extern int my_mkdir(const char *, int);
extern char * my_getcwd(char *, int);
#endif
extern int spawn_process(struct conn *c, const char *prog,
char *envblk, char *envp[], int sock, const char *dir);
/*
* io_*.c
*/
extern const struct io_class io_file;
extern const struct io_class io_socket;
extern const struct io_class io_ssl;
extern const struct io_class io_cgi;
extern const struct io_class io_dir;
extern const struct io_class io_embedded;
extern int put_dir(const char *path);
extern void get_dir(struct conn *c);
extern void get_file(struct conn *c, struct stat *stp);
extern void ssl_handshake(struct stream *stream);
extern void setup_embedded_stream(struct conn *, union variant, void *);
extern struct registered_uri *is_registered_uri(struct shttpd_ctx *,
const char *uri);
/*
* auth.c
*/
extern int check_authorization(struct conn *c, const char *path);
extern int is_authorized_for_put(struct conn *c);
extern void send_authorization_request(struct conn *c);
extern int edit_passwords(const char *fname, const char *domain,
const char *user, const char *pass);
/*
* cgi.c
*/
extern int is_cgi(struct shttpd_ctx *ctx, const char *path);
extern int run_cgi(struct conn *c, const char *prog);
extern void do_cgi(struct conn *c);
#define CGI_REPLY "HTTP/1.1 OK\r\n"
#define CGI_REPLY_LEN (sizeof(CGI_REPLY) - 1)
#endif /* DEFS_HEADER_DEFINED */
|