summaryrefslogtreecommitdiff
path: root/libafcgi.h
blob: e067bb11f149513a9dcc5334623789713e52bc3c (plain)
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
#ifndef _FCGI_CGI_FASTCGI_H
#define _FCGI_CGI_FASTCGI_H

#include "libafcgi-config.h"

/* NO multiplexing support */

#include <glib.h>
#include <ev.h>

/* FastCGI constants */
#	define FCGI_VERSION_1        1
#	define FCGI_HEADER_LEN       8

	enum FCGI_Type {
		FCGI_BEGIN_REQUEST     = 1,
		FCGI_ABORT_REQUEST     = 2,
		FCGI_END_REQUEST       = 3,
		FCGI_PARAMS            = 4,
		FCGI_STDIN             = 5,
		FCGI_STDOUT            = 6,
		FCGI_STDERR            = 7,
		FCGI_DATA              = 8,
		FCGI_GET_VALUES        = 9,
		FCGI_GET_VALUES_RESULT = 10,
		FCGI_UNKNOWN_TYPE      = 11
	};
#	define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)

	enum FCGI_Flags {
		FCGI_KEEP_CONN  = 1
	};

	enum FCGI_Role {
		FCGI_RESPONDER  = 1,
		FCGI_AUTHORIZER = 2,
		FCGI_FILTER     = 3
	};

	enum FCGI_ProtocolStatus {
		FCGI_REQUEST_COMPLETE = 0,
		FCGI_CANT_MPX_CONN    = 1,
		FCGI_OVERLOADED       = 2,
		FCGI_UNKNOWN_ROLE     = 3
	};

#define FASTCGI_MAX_KEYLEN 1024
#define FASTCGI_MAX_VALUELEN 64*1024
/* end FastCGI constants */

struct fastcgi_server;
typedef struct fastcgi_server fastcgi_server;

struct fastcgi_callbacks;
typedef struct fastcgi_callbacks fastcgi_callbacks;

struct fastcgi_connection;
typedef struct fastcgi_connection fastcgi_connection;

struct fastcgi_queue;
typedef struct fastcgi_queue fastcgi_queue;

struct fastcgi_server {
/* custom user data */
	gpointer data;

/* private data */
	gboolean do_shutdown;

	const fastcgi_callbacks *callbacks;

	guint max_connections;
	GPtrArray *connections;
	guint cur_requests;

	gint fd;
	struct ev_loop *loop;
	ev_io fd_watcher;
	ev_prepare closing_watcher;
};

struct fastcgi_callbacks {
	void (*cb_new_connection)(fastcgi_connection *fcon); /* new connection accepted */
	void (*cb_new_request)(fastcgi_connection *fcon); /* new request on connection, env/params are ready */
	void (*cb_wrote_data)(fastcgi_connection *fcon);
	void (*cb_received_stdin)(fastcgi_connection *fcon, GByteArray *data); /* data == NULL => eof */
	void (*cb_received_data)(fastcgi_connection *fcon, GByteArray *data); /* data == NULL => eof */
	void (*cb_request_aborted)(fastcgi_connection *fcon);
	void (*cb_reset_connection)(fastcgi_connection *fcon); /* cleanup custom data before fcon is freed, not for keep-alive */
};

struct fastcgi_queue {
	GQueue queue;
	gsize offset; /* offset in first chunk */
	gsize length;
	gboolean closed;
};

struct fastcgi_connection {
/* custom user data */
	gpointer data;

/* read/write */
	GHashTable *environ; /* GString -> GString */

/* read only */
	fastcgi_server *fsrv;
	guint fcon_id; /* index in server con array */
	gboolean closing; /* "dead" connection */

	/* current request */
	guint16 requestID;
	guint16 role;
	guint8 flags;

/* private data */
	unsigned char headerbuf[8];
	guint headerbuf_used;
	gboolean first;

	struct {
		guint8 version;
		guint8 type;
		guint16 requestID;
		guint16 contentLength;
		guint8 paddingLength;
	} current_header;

	guint content_remaining, padding_remaining;

	GByteArray *buffer, *parambuf;

	gint fd;
	ev_io fd_watcher;

	gboolean read_suspended;

	/* write queue */
	fastcgi_queue write_queue;
};

fastcgi_server *fastcgi_server_create(struct ev_loop *loop, gint socketfd, const fastcgi_callbacks *callbacks, guint max_connections);
void fastcgi_server_stop(fastcgi_server *fsrv); /* stop accepting new connections, closes listening socket */
void fastcgi_server_free(fastcgi_server *fsrv);

void fastcgi_suspend_read(fastcgi_connection *fcon);
void fastcgi_resume_read(fastcgi_connection *fcon);

void fastcgi_end_request(fastcgi_connection *fcon, gint32 appStatus, enum FCGI_ProtocolStatus status);
void fastcgi_send_out(fastcgi_connection *fcon, GString *data);
void fastcgi_send_err(fastcgi_connection *fcon, GString *data);
void fastcgi_send_out_bytearray(fastcgi_connection *fcon, GByteArray *data);
void fastcgi_send_err_bytearray(fastcgi_connection *fcon, GByteArray *data);

void fastcgi_connection_close(fastcgi_connection *fcon); /* shouldn't be needed */

void fastcgi_queue_append_string(fastcgi_queue *queue, GString *buf);
void fastcgi_queue_append_bytearray(fastcgi_queue *queue, GByteArray *buf);
void fastcgi_queue_clear(fastcgi_queue *queue);

/* return values: 0 ok, -1 error, -2 con closed */
gint fastcgi_queue_write(int fd, fastcgi_queue *queue, gsize max_write);

char** fastcgi_build_env(fastcgi_connection *con);
const gchar* fastcgi_connection_environ_lookup(fastcgi_connection *fcon, const gchar* key, gsize keylen);

#endif