line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#include "EVAPI.h" |
2
|
|
|
|
|
|
|
#include |
3
|
|
|
|
|
|
|
#include |
4
|
|
|
|
|
|
|
#include |
5
|
|
|
|
|
|
|
#include |
6
|
|
|
|
|
|
|
#include |
7
|
|
|
|
|
|
|
#include |
8
|
|
|
|
|
|
|
#include |
9
|
|
|
|
|
|
|
#include |
10
|
|
|
|
|
|
|
#include |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#include "ppport.h" |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////// |
16
|
|
|
|
|
|
|
// "Compile Time Options" - See Feersum.pm POD for information |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
#define MAX_HEADERS 64 |
19
|
|
|
|
|
|
|
#define MAX_HEADER_NAME_LEN 128 |
20
|
|
|
|
|
|
|
#define MAX_BODY_LEN 2147483647 |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#define READ_BUFSZ 4096 |
23
|
|
|
|
|
|
|
#define READ_INIT_FACTOR 2 |
24
|
|
|
|
|
|
|
#define READ_GROW_FACTOR 8 |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
#define AUTOCORK_WRITES 1 |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
#if 0 |
29
|
|
|
|
|
|
|
# define FLASH_SOCKET_POLICY_SUPPORT |
30
|
|
|
|
|
|
|
#endif |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
#ifndef FLASH_SOCKET_POLICY |
33
|
|
|
|
|
|
|
# define FLASH_SOCKET_POLICY "\n\n\n\n\n\n" |
34
|
|
|
|
|
|
|
#endif |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
// may be lower for your platform (e.g. Solaris is 16). See POD. |
37
|
|
|
|
|
|
|
#define FEERSUM_IOMATRIX_SIZE 64 |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
// auto-detected in Makefile.PL by perl versions and ithread usage; override |
40
|
|
|
|
|
|
|
// that here. See POD for details. |
41
|
|
|
|
|
|
|
#if 0 |
42
|
|
|
|
|
|
|
# undef FEERSUM_STEAL |
43
|
|
|
|
|
|
|
#endif |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////// |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
#ifdef __GNUC__ |
49
|
|
|
|
|
|
|
# define likely(x) __builtin_expect(!!(x), 1) |
50
|
|
|
|
|
|
|
# define unlikely(x) __builtin_expect(!!(x), 0) |
51
|
|
|
|
|
|
|
#else |
52
|
|
|
|
|
|
|
# define likely(x) (x) |
53
|
|
|
|
|
|
|
# define unlikely(x) (x) |
54
|
|
|
|
|
|
|
#endif |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
#ifndef CRLF |
57
|
|
|
|
|
|
|
#define CRLF "\015\012" |
58
|
|
|
|
|
|
|
#endif |
59
|
|
|
|
|
|
|
#define CRLFx2 CRLF CRLF |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
// make darwin, solaris and bsd happy: |
62
|
|
|
|
|
|
|
#ifndef SOL_TCP |
63
|
|
|
|
|
|
|
#define SOL_TCP IPPROTO_TCP |
64
|
|
|
|
|
|
|
#endif |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
// Wish-list: %z formats for perl sprintf. Would make compiling a lot less |
67
|
|
|
|
|
|
|
// noisy for systems that warn size_t and STRLEN are incompatible with |
68
|
|
|
|
|
|
|
// %d/%u/%x. |
69
|
|
|
|
|
|
|
#if Size_t_size == LONGSIZE |
70
|
|
|
|
|
|
|
# define Sz_f "l" |
71
|
|
|
|
|
|
|
# define Sz_t long |
72
|
|
|
|
|
|
|
#elif Size_t_size == 8 && defined HAS_QUAD && QUADKIND == QUAD_IS_LONG_LONG |
73
|
|
|
|
|
|
|
# define Sz_f "ll" |
74
|
|
|
|
|
|
|
# define Sz_t long long |
75
|
|
|
|
|
|
|
#else |
76
|
|
|
|
|
|
|
// hope "int" works. |
77
|
|
|
|
|
|
|
# define Sz_f "" |
78
|
|
|
|
|
|
|
# define Sz_t int |
79
|
|
|
|
|
|
|
#endif |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
#define Sz_uf Sz_f"u" |
82
|
|
|
|
|
|
|
#define Sz_xf Sz_f"x" |
83
|
|
|
|
|
|
|
#define Ssz_df Sz_f"d" |
84
|
|
|
|
|
|
|
#define Sz unsigned Sz_t |
85
|
|
|
|
|
|
|
#define Ssz Sz_t |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
#define WARN_PREFIX "Feersum: " |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
#ifndef DEBUG |
90
|
|
|
|
|
|
|
#ifndef __inline |
91
|
|
|
|
|
|
|
#define __inline |
92
|
|
|
|
|
|
|
#endif |
93
|
|
|
|
|
|
|
#define INLINE_UNLESS_DEBUG __inline |
94
|
|
|
|
|
|
|
#else |
95
|
|
|
|
|
|
|
#define INLINE_UNLESS_DEBUG |
96
|
|
|
|
|
|
|
#endif |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
#define trouble(f_, ...) warn(WARN_PREFIX f_, ##__VA_ARGS__); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
#ifdef DEBUG |
101
|
|
|
|
|
|
|
#define trace(f_, ...) warn("%s:%-4d [%d] " f_, __FILE__, __LINE__, (int)getpid(), ##__VA_ARGS__) |
102
|
|
|
|
|
|
|
#else |
103
|
|
|
|
|
|
|
#define trace(...) |
104
|
|
|
|
|
|
|
#endif |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
#if DEBUG >= 2 |
107
|
|
|
|
|
|
|
#define trace2(f_, ...) trace(f_, ##__VA_ARGS__) |
108
|
|
|
|
|
|
|
#else |
109
|
|
|
|
|
|
|
#define trace2(...) |
110
|
|
|
|
|
|
|
#endif |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
#if DEBUG >= 3 |
113
|
|
|
|
|
|
|
#define trace3(f_, ...) trace(f_, ##__VA_ARGS__) |
114
|
|
|
|
|
|
|
#else |
115
|
|
|
|
|
|
|
#define trace3(...) |
116
|
|
|
|
|
|
|
#endif |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
#include "picohttpparser-git/picohttpparser.c" |
119
|
|
|
|
|
|
|
#include "rinq.c" |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
// Check FEERSUM_IOMATRIX_SIZE against what's actually usable on this |
122
|
|
|
|
|
|
|
// platform. See Feersum.pm for an explanation |
123
|
|
|
|
|
|
|
#if defined(IOV_MAX) && FEERSUM_IOMATRIX_SIZE > IOV_MAX |
124
|
|
|
|
|
|
|
# undef FEERSUM_IOMATRIX_SIZE |
125
|
|
|
|
|
|
|
# define FEERSUM_IOMATRIX_SIZE IOV_MAX |
126
|
|
|
|
|
|
|
#elif defined(UIO_MAXIOV) && FEERSUM_IOMATRIX_SIZE > UIO_MAXIOV |
127
|
|
|
|
|
|
|
# undef FEERSUM_IOMATRIX_SIZE |
128
|
|
|
|
|
|
|
# define FEERSUM_IOMATRIX_SIZE UIO_MAXIOV |
129
|
|
|
|
|
|
|
#endif |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
struct iomatrix { |
132
|
|
|
|
|
|
|
unsigned offset; |
133
|
|
|
|
|
|
|
unsigned count; |
134
|
|
|
|
|
|
|
struct iovec iov[FEERSUM_IOMATRIX_SIZE]; |
135
|
|
|
|
|
|
|
SV *sv[FEERSUM_IOMATRIX_SIZE]; |
136
|
|
|
|
|
|
|
}; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
struct feer_req { |
139
|
|
|
|
|
|
|
SV *buf; |
140
|
|
|
|
|
|
|
const char* method; |
141
|
|
|
|
|
|
|
size_t method_len; |
142
|
|
|
|
|
|
|
const char* path; |
143
|
|
|
|
|
|
|
size_t path_len; |
144
|
|
|
|
|
|
|
int minor_version; |
145
|
|
|
|
|
|
|
size_t num_headers; |
146
|
|
|
|
|
|
|
struct phr_header headers[MAX_HEADERS]; |
147
|
|
|
|
|
|
|
}; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
enum feer_respond_state { |
150
|
|
|
|
|
|
|
RESPOND_NOT_STARTED = 0, |
151
|
|
|
|
|
|
|
RESPOND_NORMAL = 1, |
152
|
|
|
|
|
|
|
RESPOND_STREAMING = 2, |
153
|
|
|
|
|
|
|
RESPOND_SHUTDOWN = 3 |
154
|
|
|
|
|
|
|
}; |
155
|
|
|
|
|
|
|
#define RESPOND_STR(_n,_s) do { \ |
156
|
|
|
|
|
|
|
switch(_n) { \ |
157
|
|
|
|
|
|
|
case RESPOND_NOT_STARTED: _s = "NOT_STARTED(0)"; break; \ |
158
|
|
|
|
|
|
|
case RESPOND_NORMAL: _s = "NORMAL(1)"; break; \ |
159
|
|
|
|
|
|
|
case RESPOND_STREAMING: _s = "STREAMING(2)"; break; \ |
160
|
|
|
|
|
|
|
case RESPOND_SHUTDOWN: _s = "SHUTDOWN(4)"; break; \ |
161
|
|
|
|
|
|
|
} \ |
162
|
|
|
|
|
|
|
} while (0) |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
enum feer_receive_state { |
165
|
|
|
|
|
|
|
RECEIVE_HEADERS = 0, |
166
|
|
|
|
|
|
|
RECEIVE_BODY = 1, |
167
|
|
|
|
|
|
|
RECEIVE_STREAMING = 2, |
168
|
|
|
|
|
|
|
RECEIVE_SHUTDOWN = 3 |
169
|
|
|
|
|
|
|
}; |
170
|
|
|
|
|
|
|
#define RECEIVE_STR(_n,_s) do { \ |
171
|
|
|
|
|
|
|
switch(_n) { \ |
172
|
|
|
|
|
|
|
case RECEIVE_HEADERS: _s = "HEADERS(0)"; break; \ |
173
|
|
|
|
|
|
|
case RECEIVE_BODY: _s = "BODY(1)"; break; \ |
174
|
|
|
|
|
|
|
case RECEIVE_STREAMING: _s = "STREAMING(2)"; break; \ |
175
|
|
|
|
|
|
|
case RECEIVE_SHUTDOWN: _s = "SHUTDOWN(3)"; break; \ |
176
|
|
|
|
|
|
|
} \ |
177
|
|
|
|
|
|
|
} while (0) |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
struct feer_conn { |
180
|
|
|
|
|
|
|
SV *self; |
181
|
|
|
|
|
|
|
int fd; |
182
|
|
|
|
|
|
|
struct sockaddr *sa; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
struct ev_io read_ev_io; |
185
|
|
|
|
|
|
|
struct ev_io write_ev_io; |
186
|
|
|
|
|
|
|
struct ev_timer read_ev_timer; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
SV *rbuf; |
189
|
|
|
|
|
|
|
struct rinq *wbuf_rinq; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
SV *poll_write_cb; |
192
|
|
|
|
|
|
|
SV *ext_guard; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
struct feer_req *req; |
195
|
|
|
|
|
|
|
ssize_t expected_cl; |
196
|
|
|
|
|
|
|
ssize_t received_cl; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
enum feer_respond_state responding; |
199
|
|
|
|
|
|
|
enum feer_receive_state receiving; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
int in_callback; |
202
|
|
|
|
|
|
|
int is_http11:1; |
203
|
|
|
|
|
|
|
int poll_write_cb_is_io_handle:1; |
204
|
|
|
|
|
|
|
int auto_cl:1; |
205
|
|
|
|
|
|
|
}; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
typedef struct feer_conn feer_conn_handle; // for typemap |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
#define dCONN struct feer_conn *c = (struct feer_conn *)w->data |
210
|
|
|
|
|
|
|
#define IsArrayRef(_x) (SvROK(_x) && SvTYPE(SvRV(_x)) == SVt_PVAV) |
211
|
|
|
|
|
|
|
#define IsCodeRef(_x) (SvROK(_x) && SvTYPE(SvRV(_x)) == SVt_PVCV) |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
static HV* feersum_env(pTHX_ struct feer_conn *c); |
214
|
|
|
|
|
|
|
static void feersum_start_response |
215
|
|
|
|
|
|
|
(pTHX_ struct feer_conn *c, SV *message, AV *headers, int streaming); |
216
|
|
|
|
|
|
|
static size_t feersum_write_whole_body (pTHX_ struct feer_conn *c, SV *body); |
217
|
|
|
|
|
|
|
static void feersum_handle_psgi_response( |
218
|
|
|
|
|
|
|
pTHX_ struct feer_conn *c, SV *ret, bool can_recurse); |
219
|
|
|
|
|
|
|
static int feersum_close_handle(pTHX_ struct feer_conn *c, bool is_writer); |
220
|
|
|
|
|
|
|
static SV* feersum_conn_guard(pTHX_ struct feer_conn *c, SV *guard); |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
static void start_read_watcher(struct feer_conn *c); |
223
|
|
|
|
|
|
|
static void stop_read_watcher(struct feer_conn *c); |
224
|
|
|
|
|
|
|
static void restart_read_timer(struct feer_conn *c); |
225
|
|
|
|
|
|
|
static void stop_read_timer(struct feer_conn *c); |
226
|
|
|
|
|
|
|
static void start_write_watcher(struct feer_conn *c); |
227
|
|
|
|
|
|
|
static void stop_write_watcher(struct feer_conn *c); |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
static void try_conn_write(EV_P_ struct ev_io *w, int revents); |
230
|
|
|
|
|
|
|
static void try_conn_read(EV_P_ struct ev_io *w, int revents); |
231
|
|
|
|
|
|
|
static void conn_read_timeout(EV_P_ struct ev_timer *w, int revents); |
232
|
|
|
|
|
|
|
static bool process_request_headers(struct feer_conn *c, int body_offset); |
233
|
|
|
|
|
|
|
static void sched_request_callback(struct feer_conn *c); |
234
|
|
|
|
|
|
|
static void call_died (pTHX_ struct feer_conn *c, const char *cb_type); |
235
|
|
|
|
|
|
|
static void call_request_callback(struct feer_conn *c); |
236
|
|
|
|
|
|
|
static void call_poll_callback (struct feer_conn *c, bool is_write); |
237
|
|
|
|
|
|
|
static void pump_io_handle (struct feer_conn *c, SV *io); |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
static void conn_write_ready (struct feer_conn *c); |
240
|
|
|
|
|
|
|
static void respond_with_server_error(struct feer_conn *c, const char *msg, STRLEN msg_len, int code); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
static void update_wbuf_placeholder(struct feer_conn *c, SV *sv, struct iovec *iov); |
243
|
|
|
|
|
|
|
static STRLEN add_sv_to_wbuf (struct feer_conn *c, SV *sv); |
244
|
|
|
|
|
|
|
static STRLEN add_const_to_wbuf (struct feer_conn *c, const char *str, size_t str_len); |
245
|
|
|
|
|
|
|
#define add_crlf_to_wbuf(c) add_const_to_wbuf(c,CRLF,2) |
246
|
|
|
|
|
|
|
static void finish_wbuf (struct feer_conn *c); |
247
|
|
|
|
|
|
|
static void add_chunk_sv_to_wbuf (struct feer_conn *c, SV *sv); |
248
|
|
|
|
|
|
|
static void add_placeholder_to_wbuf (struct feer_conn *c, SV **sv, struct iovec **iov_ref); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
static void uri_decode_sv (SV *sv); |
251
|
|
|
|
|
|
|
static bool str_eq(const char *a, int a_len, const char *b, int b_len); |
252
|
|
|
|
|
|
|
static bool str_case_eq(const char *a, int a_len, const char *b, int b_len); |
253
|
|
|
|
|
|
|
static SV* fetch_av_normal (pTHX_ AV *av, I32 i); |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
static const char *http_code_to_msg (int code); |
256
|
|
|
|
|
|
|
static int prep_socket (int fd, int is_tcp); |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
static HV *feer_stash, *feer_conn_stash; |
259
|
|
|
|
|
|
|
static HV *feer_conn_reader_stash = NULL, *feer_conn_writer_stash = NULL; |
260
|
|
|
|
|
|
|
static MGVTBL psgix_io_vtbl; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
static SV *request_cb_cv = NULL; |
263
|
|
|
|
|
|
|
static bool request_cb_is_psgi = 0; |
264
|
|
|
|
|
|
|
static SV *shutdown_cb_cv = NULL; |
265
|
|
|
|
|
|
|
static bool shutting_down = 0; |
266
|
|
|
|
|
|
|
static int active_conns = 0; |
267
|
|
|
|
|
|
|
static double read_timeout = 5.0; |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
static SV *feer_server_name = NULL; |
270
|
|
|
|
|
|
|
static SV *feer_server_port = NULL; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
static ev_io accept_w; |
273
|
|
|
|
|
|
|
static ev_prepare ep; |
274
|
|
|
|
|
|
|
static ev_check ec; |
275
|
|
|
|
|
|
|
struct ev_idle ei; |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
static struct rinq *request_ready_rinq = NULL; |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
static AV *psgi_ver; |
280
|
|
|
|
|
|
|
static SV *psgi_serv10, *psgi_serv11, *crlf_sv; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
// TODO: make this thread-local if and when there are multiple C threads: |
283
|
|
|
|
|
|
|
struct ev_loop *feersum_ev_loop = NULL; |
284
|
|
|
|
|
|
|
static HV *feersum_tmpl_env = NULL; |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
287
|
|
|
|
|
|
|
static SV* |
288
|
101
|
|
|
|
|
|
fetch_av_normal (pTHX_ AV *av, I32 i) |
289
|
|
|
|
|
|
|
{ |
290
|
101
|
|
|
|
|
|
SV **elt = av_fetch(av, i, 0); |
291
|
101
|
50
|
|
|
|
|
if (elt == NULL) return NULL; |
292
|
101
|
|
|
|
|
|
SV *sv = *elt; |
293
|
|
|
|
|
|
|
// copy to remove magic |
294
|
101
|
100
|
|
|
|
|
if (unlikely(SvMAGICAL(sv))) sv = sv_2mortal(newSVsv(sv)); |
295
|
101
|
100
|
|
|
|
|
if (unlikely(!SvOK(sv))) return NULL; |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
296
|
|
|
|
|
|
|
// usually array ref elems aren't RVs (for PSGI anyway) |
297
|
98
|
100
|
|
|
|
|
if (unlikely(SvROK(sv))) sv = SvRV(sv); |
298
|
98
|
|
|
|
|
|
return sv; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
302
|
|
|
|
|
|
|
static struct iomatrix * |
303
|
1193
|
|
|
|
|
|
next_iomatrix (struct feer_conn *c) |
304
|
|
|
|
|
|
|
{ |
305
|
1193
|
|
|
|
|
|
bool add_iomatrix = 0; |
306
|
|
|
|
|
|
|
struct iomatrix *m; |
307
|
|
|
|
|
|
|
|
308
|
1193
|
100
|
|
|
|
|
if (!c->wbuf_rinq) { |
309
|
|
|
|
|
|
|
trace3("next_iomatrix(%d): head\n", c->fd); |
310
|
156
|
|
|
|
|
|
add_iomatrix = 1; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
else { |
313
|
|
|
|
|
|
|
// get the tail-end struct |
314
|
1037
|
|
|
|
|
|
m = (struct iomatrix *)c->wbuf_rinq->prev->ref; |
315
|
|
|
|
|
|
|
trace3("next_iomatrix(%d): tail, count=%d, offset=%d\n", |
316
|
|
|
|
|
|
|
c->fd, m->count, m->offset); |
317
|
1037
|
50
|
|
|
|
|
if (m->count >= FEERSUM_IOMATRIX_SIZE) { |
318
|
0
|
|
|
|
|
|
add_iomatrix = 1; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
1193
|
100
|
|
|
|
|
if (add_iomatrix) { |
323
|
|
|
|
|
|
|
trace3("next_iomatrix(%d): malloc\n", c->fd); |
324
|
156
|
|
|
|
|
|
Newx(m,1,struct iomatrix); |
325
|
156
|
|
|
|
|
|
Poison(m,1,struct iomatrix); |
326
|
156
|
|
|
|
|
|
m->offset = m->count = 0; |
327
|
156
|
|
|
|
|
|
rinq_push(&c->wbuf_rinq, m); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
trace3("next_iomatrix(%d): end, count=%d, offset=%d\n", |
331
|
|
|
|
|
|
|
c->fd, m->count, m->offset); |
332
|
1193
|
|
|
|
|
|
return m; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
336
|
|
|
|
|
|
|
static STRLEN |
337
|
517
|
|
|
|
|
|
add_sv_to_wbuf(struct feer_conn *c, SV *sv) |
338
|
|
|
|
|
|
|
{ |
339
|
517
|
|
|
|
|
|
struct iomatrix *m = next_iomatrix(c); |
340
|
517
|
|
|
|
|
|
int idx = m->count++; |
341
|
|
|
|
|
|
|
STRLEN cur; |
342
|
517
|
100
|
|
|
|
|
if (unlikely(SvMAGICAL(sv))) { |
343
|
2
|
|
|
|
|
|
sv = newSVsv(sv); // copy to force it to be normal. |
344
|
|
|
|
|
|
|
} |
345
|
515
|
50
|
|
|
|
|
else if (unlikely(SvPADTMP(sv))) { |
346
|
|
|
|
|
|
|
// PADTMPs have their PVs re-used, so we can't simply keep a |
347
|
|
|
|
|
|
|
// reference. TEMPs maybe behave in a similar way and are potentially |
348
|
|
|
|
|
|
|
// stealable. If not stealing, we must make a copy. |
349
|
|
|
|
|
|
|
#ifdef FEERSUM_STEAL |
350
|
0
|
0
|
|
|
|
|
if (SvFLAGS(sv) == (SVs_PADTMP|SVf_POK|SVp_POK)) { |
351
|
|
|
|
|
|
|
trace3("STEALING\n"); |
352
|
0
|
|
|
|
|
|
SV *theif = newSV(0); |
353
|
0
|
|
|
|
|
|
sv_upgrade(theif, SVt_PV); |
354
|
|
|
|
|
|
|
|
355
|
0
|
|
|
|
|
|
SvPV_set(theif, SvPVX(sv)); |
356
|
0
|
|
|
|
|
|
SvLEN_set(theif, SvLEN(sv)); |
357
|
0
|
|
|
|
|
|
SvCUR_set(theif, SvCUR(sv)); |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
// make the temp null |
360
|
0
|
0
|
|
|
|
|
(void)SvOK_off(sv); |
361
|
0
|
|
|
|
|
|
SvPV_set(sv, NULL); |
362
|
0
|
|
|
|
|
|
SvLEN_set(sv, 0); |
363
|
0
|
|
|
|
|
|
SvCUR_set(sv, 0); |
364
|
|
|
|
|
|
|
|
365
|
0
|
|
|
|
|
|
SvFLAGS(theif) |= SVf_READONLY|SVf_POK|SVp_POK; |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
|
sv = theif; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
else { |
370
|
0
|
|
|
|
|
|
sv = newSVsv(sv); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
#else |
373
|
|
|
|
|
|
|
sv = newSVsv(sv); |
374
|
|
|
|
|
|
|
#endif |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
else { |
377
|
515
|
|
|
|
|
|
sv = SvREFCNT_inc(sv); |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
517
|
100
|
|
|
|
|
m->iov[idx].iov_base = SvPV(sv, cur); |
381
|
517
|
|
|
|
|
|
m->iov[idx].iov_len = cur; |
382
|
517
|
|
|
|
|
|
m->sv[idx] = sv; |
383
|
|
|
|
|
|
|
|
384
|
517
|
|
|
|
|
|
return cur; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
388
|
|
|
|
|
|
|
static STRLEN |
389
|
561
|
|
|
|
|
|
add_const_to_wbuf(struct feer_conn *c, const char *str, size_t str_len) |
390
|
|
|
|
|
|
|
{ |
391
|
561
|
|
|
|
|
|
struct iomatrix *m = next_iomatrix(c); |
392
|
561
|
|
|
|
|
|
int idx = m->count++; |
393
|
561
|
|
|
|
|
|
m->iov[idx].iov_base = (void*)str; |
394
|
561
|
|
|
|
|
|
m->iov[idx].iov_len = str_len; |
395
|
561
|
|
|
|
|
|
m->sv[idx] = NULL; |
396
|
561
|
|
|
|
|
|
return str_len; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
400
|
|
|
|
|
|
|
static void |
401
|
115
|
|
|
|
|
|
add_placeholder_to_wbuf(struct feer_conn *c, SV **sv, struct iovec **iov_ref) |
402
|
|
|
|
|
|
|
{ |
403
|
115
|
|
|
|
|
|
struct iomatrix *m = next_iomatrix(c); |
404
|
115
|
|
|
|
|
|
int idx = m->count++; |
405
|
115
|
|
|
|
|
|
*sv = newSV(31); |
406
|
115
|
|
|
|
|
|
SvPOK_on(*sv); |
407
|
115
|
|
|
|
|
|
m->sv[idx] = *sv; |
408
|
115
|
|
|
|
|
|
*iov_ref = &m->iov[idx]; |
409
|
115
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
412
|
|
|
|
|
|
|
static void |
413
|
28
|
|
|
|
|
|
finish_wbuf(struct feer_conn *c) |
414
|
|
|
|
|
|
|
{ |
415
|
28
|
100
|
|
|
|
|
if (!c->is_http11) return; // nothing required |
416
|
24
|
|
|
|
|
|
add_const_to_wbuf(c, "0\r\n\r\n", 5); // terminating chunk |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
420
|
|
|
|
|
|
|
static void |
421
|
115
|
|
|
|
|
|
update_wbuf_placeholder(struct feer_conn *c, SV *sv, struct iovec *iov) |
422
|
|
|
|
|
|
|
{ |
423
|
|
|
|
|
|
|
STRLEN cur; |
424
|
|
|
|
|
|
|
// can't pass iov_len for cur; incompatible pointer type on some systems: |
425
|
115
|
50
|
|
|
|
|
iov->iov_base = SvPV(sv,cur); |
426
|
115
|
|
|
|
|
|
iov->iov_len = cur; |
427
|
115
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
static void |
430
|
48
|
|
|
|
|
|
add_chunk_sv_to_wbuf(struct feer_conn *c, SV *sv) |
431
|
|
|
|
|
|
|
{ |
432
|
|
|
|
|
|
|
SV *chunk; |
433
|
|
|
|
|
|
|
struct iovec *chunk_iov; |
434
|
48
|
|
|
|
|
|
add_placeholder_to_wbuf(c, &chunk, &chunk_iov); |
435
|
48
|
|
|
|
|
|
STRLEN cur = add_sv_to_wbuf(c, sv); |
436
|
48
|
|
|
|
|
|
add_crlf_to_wbuf(c); |
437
|
48
|
|
|
|
|
|
sv_setpvf(chunk, "%"Sz_xf CRLF, (Sz)cur); |
438
|
48
|
|
|
|
|
|
update_wbuf_placeholder(c, chunk, chunk_iov); |
439
|
48
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
static const char * |
442
|
83
|
|
|
|
|
|
http_code_to_msg (int code) { |
443
|
|
|
|
|
|
|
// http://en.wikipedia.org/wiki/List_of_HTTP_status_codes |
444
|
83
|
|
|
|
|
|
switch (code) { |
445
|
0
|
|
|
|
|
|
case 100: return "Continue"; |
446
|
0
|
|
|
|
|
|
case 101: return "Switching Protocols"; |
447
|
0
|
|
|
|
|
|
case 102: return "Processing"; // RFC 2518 |
448
|
74
|
|
|
|
|
|
case 200: return "OK"; |
449
|
0
|
|
|
|
|
|
case 201: return "Created"; |
450
|
0
|
|
|
|
|
|
case 202: return "Accepted"; |
451
|
0
|
|
|
|
|
|
case 203: return "Non Authoritative Information"; |
452
|
0
|
|
|
|
|
|
case 204: return "No Content"; |
453
|
0
|
|
|
|
|
|
case 205: return "Reset Content"; |
454
|
0
|
|
|
|
|
|
case 206: return "Partial Content"; |
455
|
0
|
|
|
|
|
|
case 207: return "Multi-Status"; // RFC 4918 (WebDav) |
456
|
0
|
|
|
|
|
|
case 300: return "Multiple Choices"; |
457
|
0
|
|
|
|
|
|
case 301: return "Moved Permanently"; |
458
|
1
|
|
|
|
|
|
case 302: return "Found"; |
459
|
0
|
|
|
|
|
|
case 303: return "See Other"; |
460
|
2
|
|
|
|
|
|
case 304: return "Not Modified"; |
461
|
0
|
|
|
|
|
|
case 305: return "Use Proxy"; |
462
|
0
|
|
|
|
|
|
case 307: return "Temporary Redirect"; |
463
|
1
|
|
|
|
|
|
case 400: return "Bad Request"; |
464
|
0
|
|
|
|
|
|
case 401: return "Unauthorized"; |
465
|
0
|
|
|
|
|
|
case 402: return "Payment Required"; |
466
|
0
|
|
|
|
|
|
case 403: return "Forbidden"; |
467
|
1
|
|
|
|
|
|
case 404: return "Not Found"; |
468
|
0
|
|
|
|
|
|
case 405: return "Method Not Allowed"; |
469
|
0
|
|
|
|
|
|
case 406: return "Not Acceptable"; |
470
|
0
|
|
|
|
|
|
case 407: return "Proxy Authentication Required"; |
471
|
2
|
|
|
|
|
|
case 408: return "Request Timeout"; |
472
|
0
|
|
|
|
|
|
case 409: return "Conflict"; |
473
|
0
|
|
|
|
|
|
case 410: return "Gone"; |
474
|
0
|
|
|
|
|
|
case 411: return "Length Required"; |
475
|
0
|
|
|
|
|
|
case 412: return "Precondition Failed"; |
476
|
0
|
|
|
|
|
|
case 413: return "Request Entity Too Large"; |
477
|
0
|
|
|
|
|
|
case 414: return "Request URI Too Long"; |
478
|
0
|
|
|
|
|
|
case 415: return "Unsupported Media Type"; |
479
|
0
|
|
|
|
|
|
case 416: return "Requested Range Not Satisfiable"; |
480
|
0
|
|
|
|
|
|
case 417: return "Expectation Failed"; |
481
|
0
|
|
|
|
|
|
case 418: return "I'm a teapot"; |
482
|
0
|
|
|
|
|
|
case 421: return "Too Many Connections"; // Microsoft? |
483
|
0
|
|
|
|
|
|
case 422: return "Unprocessable Entity"; // RFC 4918 |
484
|
0
|
|
|
|
|
|
case 423: return "Locked"; // RFC 4918 |
485
|
0
|
|
|
|
|
|
case 424: return "Failed Dependency"; // RFC 4918 |
486
|
0
|
|
|
|
|
|
case 425: return "Unordered Collection"; // RFC 3648 |
487
|
0
|
|
|
|
|
|
case 426: return "Upgrade Required"; // RFC 2817 |
488
|
0
|
|
|
|
|
|
case 449: return "Retry With"; // Microsoft |
489
|
0
|
|
|
|
|
|
case 450: return "Blocked by Parental Controls"; // Microsoft |
490
|
2
|
|
|
|
|
|
case 500: return "Internal Server Error"; |
491
|
0
|
|
|
|
|
|
case 501: return "Not Implemented"; |
492
|
0
|
|
|
|
|
|
case 502: return "Bad Gateway"; |
493
|
0
|
|
|
|
|
|
case 503: return "Service Unavailable"; |
494
|
0
|
|
|
|
|
|
case 504: return "Gateway Timeout"; |
495
|
0
|
|
|
|
|
|
case 505: return "HTTP Version Not Supported"; |
496
|
0
|
|
|
|
|
|
case 506: return "Variant Also Negotiates"; // RFC 2295 |
497
|
0
|
|
|
|
|
|
case 507: return "Insufficient Storage"; // RFC 4918 |
498
|
0
|
|
|
|
|
|
case 509: return "Bandwidth Limit Exceeded"; // Apache mod |
499
|
0
|
|
|
|
|
|
case 510: return "Not Extended"; // RFC 2774 |
500
|
0
|
|
|
|
|
|
case 530: return "User access denied"; // ?? |
501
|
0
|
|
|
|
|
|
default: break; |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
// default to the Nxx group names in RFC 2616 |
505
|
0
|
0
|
|
|
|
|
if (100 <= code && code <= 199) { |
|
|
0
|
|
|
|
|
|
506
|
0
|
|
|
|
|
|
return "Informational"; |
507
|
|
|
|
|
|
|
} |
508
|
0
|
0
|
|
|
|
|
else if (200 <= code && code <= 299) { |
|
|
0
|
|
|
|
|
|
509
|
0
|
|
|
|
|
|
return "Success"; |
510
|
|
|
|
|
|
|
} |
511
|
0
|
0
|
|
|
|
|
else if (300 <= code && code <= 399) { |
|
|
0
|
|
|
|
|
|
512
|
0
|
|
|
|
|
|
return "Redirection"; |
513
|
|
|
|
|
|
|
} |
514
|
0
|
0
|
|
|
|
|
else if (400 <= code && code <= 499) { |
|
|
0
|
|
|
|
|
|
515
|
0
|
|
|
|
|
|
return "Client Error"; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
else { |
518
|
0
|
|
|
|
|
|
return "Error"; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
static int |
523
|
118
|
|
|
|
|
|
prep_socket(int fd, int is_tcp) |
524
|
|
|
|
|
|
|
{ |
525
|
|
|
|
|
|
|
int flags; |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
// make it non-blocking |
528
|
118
|
|
|
|
|
|
flags = O_NONBLOCK; |
529
|
118
|
50
|
|
|
|
|
if (unlikely(fcntl(fd, F_SETFL, flags) < 0)) |
530
|
0
|
|
|
|
|
|
return -1; |
531
|
|
|
|
|
|
|
|
532
|
118
|
50
|
|
|
|
|
if (likely(is_tcp)) { |
533
|
|
|
|
|
|
|
// flush writes immediately |
534
|
118
|
|
|
|
|
|
flags = 1; |
535
|
118
|
50
|
|
|
|
|
if (unlikely(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flags, sizeof(int)))) |
536
|
0
|
|
|
|
|
|
return -1; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
// handle URG data inline |
540
|
118
|
|
|
|
|
|
flags = 1; |
541
|
118
|
50
|
|
|
|
|
if (unlikely(setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &flags, sizeof(int)))) |
542
|
0
|
|
|
|
|
|
return -1; |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
// disable lingering |
545
|
118
|
|
|
|
|
|
struct linger linger = { .l_onoff = 0, .l_linger = 0 }; |
546
|
118
|
50
|
|
|
|
|
if (unlikely(setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)))) |
547
|
0
|
|
|
|
|
|
return -1; |
548
|
|
|
|
|
|
|
|
549
|
118
|
|
|
|
|
|
return 0; |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
553
|
221
|
|
|
|
|
|
safe_close_conn(struct feer_conn *c, const char *where) |
554
|
|
|
|
|
|
|
{ |
555
|
221
|
100
|
|
|
|
|
if (unlikely(c->fd < 0)) |
556
|
103
|
|
|
|
|
|
return; |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
// make it blocking |
559
|
118
|
|
|
|
|
|
fcntl(c->fd, F_SETFL, 0); |
560
|
|
|
|
|
|
|
|
561
|
118
|
50
|
|
|
|
|
if (unlikely(close(c->fd))) |
562
|
0
|
|
|
|
|
|
perror(where); |
563
|
|
|
|
|
|
|
|
564
|
118
|
|
|
|
|
|
c->fd = -1; |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
static struct feer_conn * |
568
|
118
|
|
|
|
|
|
new_feer_conn (EV_P_ int conn_fd, struct sockaddr *sa) |
569
|
|
|
|
|
|
|
{ |
570
|
118
|
|
|
|
|
|
SV *self = newSV(0); |
571
|
118
|
50
|
|
|
|
|
SvUPGRADE(self, SVt_PVMG); // ensures sv_bless doesn't reallocate |
572
|
118
|
50
|
|
|
|
|
SvGROW(self, sizeof(struct feer_conn)); |
|
|
50
|
|
|
|
|
|
573
|
118
|
|
|
|
|
|
SvPOK_only(self); |
574
|
118
|
|
|
|
|
|
SvIOK_on(self); |
575
|
118
|
|
|
|
|
|
SvIV_set(self,conn_fd); |
576
|
|
|
|
|
|
|
|
577
|
118
|
|
|
|
|
|
struct feer_conn *c = (struct feer_conn *)SvPVX(self); |
578
|
118
|
|
|
|
|
|
Zero(c, 1, struct feer_conn); |
579
|
|
|
|
|
|
|
|
580
|
118
|
|
|
|
|
|
c->self = self; |
581
|
118
|
|
|
|
|
|
c->fd = conn_fd; |
582
|
118
|
|
|
|
|
|
c->sa = sa; |
583
|
118
|
|
|
|
|
|
c->responding = RESPOND_NOT_STARTED; |
584
|
118
|
|
|
|
|
|
c->receiving = RECEIVE_HEADERS; |
585
|
|
|
|
|
|
|
|
586
|
118
|
|
|
|
|
|
ev_io_init(&c->read_ev_io, try_conn_read, conn_fd, EV_READ); |
587
|
118
|
|
|
|
|
|
c->read_ev_io.data = (void *)c; |
588
|
|
|
|
|
|
|
|
589
|
118
|
|
|
|
|
|
ev_init(&c->read_ev_timer, conn_read_timeout); |
590
|
118
|
|
|
|
|
|
c->read_ev_timer.data = (void *)c; |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
trace3("made conn fd=%d self=%p, c=%p, cur=%"Sz_uf", len=%"Sz_uf"\n", |
593
|
|
|
|
|
|
|
c->fd, self, c, (Sz)SvCUR(self), (Sz)SvLEN(self)); |
594
|
|
|
|
|
|
|
|
595
|
118
|
|
|
|
|
|
SV *rv = newRV_inc(c->self); |
596
|
118
|
|
|
|
|
|
sv_bless(rv, feer_conn_stash); // so DESTROY can get called on read errors |
597
|
118
|
|
|
|
|
|
SvREFCNT_dec(rv); |
598
|
|
|
|
|
|
|
|
599
|
118
|
|
|
|
|
|
SvREADONLY_on(self); // turn off later for blessing |
600
|
118
|
|
|
|
|
|
active_conns++; |
601
|
118
|
|
|
|
|
|
return c; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
// for use in the typemap: |
605
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
606
|
|
|
|
|
|
|
static struct feer_conn * |
607
|
204
|
|
|
|
|
|
sv_2feer_conn (SV *rv) |
608
|
|
|
|
|
|
|
{ |
609
|
204
|
50
|
|
|
|
|
if (unlikely(!sv_isa(rv,"Feersum::Connection"))) |
610
|
0
|
|
|
|
|
|
croak("object is not of type Feersum::Connection"); |
611
|
204
|
|
|
|
|
|
return (struct feer_conn *)SvPVX(SvRV(rv)); |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG |
615
|
|
|
|
|
|
|
static SV* |
616
|
125
|
|
|
|
|
|
feer_conn_2sv (struct feer_conn *c) |
617
|
|
|
|
|
|
|
{ |
618
|
125
|
|
|
|
|
|
return newRV_inc(c->self); |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
static feer_conn_handle * |
622
|
108
|
|
|
|
|
|
sv_2feer_conn_handle (SV *rv, bool can_croak) |
623
|
|
|
|
|
|
|
{ |
624
|
|
|
|
|
|
|
trace3("sv 2 conn_handle\n"); |
625
|
108
|
50
|
|
|
|
|
if (unlikely(!SvROK(rv))) croak("Expected a reference"); |
626
|
|
|
|
|
|
|
// do not allow subclassing |
627
|
108
|
|
|
|
|
|
SV *sv = SvRV(rv); |
628
|
108
|
50
|
|
|
|
|
if (likely( |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
629
|
|
|
|
|
|
|
sv_isobject(rv) && |
630
|
|
|
|
|
|
|
(SvSTASH(sv) == feer_conn_writer_stash || |
631
|
|
|
|
|
|
|
SvSTASH(sv) == feer_conn_reader_stash) |
632
|
|
|
|
|
|
|
)) { |
633
|
108
|
50
|
|
|
|
|
UV uv = SvUV(sv); |
634
|
108
|
100
|
|
|
|
|
if (uv == 0) { |
635
|
21
|
100
|
|
|
|
|
if (can_croak) croak("Operation not allowed: Handle is closed."); |
636
|
17
|
|
|
|
|
|
return NULL; |
637
|
|
|
|
|
|
|
} |
638
|
87
|
|
|
|
|
|
return INT2PTR(feer_conn_handle*,uv); |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
0
|
0
|
|
|
|
|
if (can_croak) |
642
|
0
|
|
|
|
|
|
croak("Expected a Feersum::Connection::Writer or ::Reader object"); |
643
|
0
|
|
|
|
|
|
return NULL; |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
static SV * |
647
|
28
|
|
|
|
|
|
new_feer_conn_handle (pTHX_ struct feer_conn *c, bool is_writer) |
648
|
|
|
|
|
|
|
{ |
649
|
|
|
|
|
|
|
SV *sv; |
650
|
28
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
651
|
28
|
|
|
|
|
|
sv = newRV_noinc(newSVuv(PTR2UV(c))); |
652
|
28
|
100
|
|
|
|
|
sv_bless(sv, is_writer ? feer_conn_writer_stash : feer_conn_reader_stash); |
653
|
28
|
|
|
|
|
|
return sv; |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
#if DEBUG |
657
|
|
|
|
|
|
|
# define change_responding_state(c, _to) do { \ |
658
|
|
|
|
|
|
|
enum feer_respond_state __to = (_to); \ |
659
|
|
|
|
|
|
|
enum feer_respond_state __from = c->responding; \ |
660
|
|
|
|
|
|
|
const char *_from_str, *_to_str; \ |
661
|
|
|
|
|
|
|
if (likely(__from != __to)) { \ |
662
|
|
|
|
|
|
|
RESPOND_STR(c->responding, _from_str); \ |
663
|
|
|
|
|
|
|
RESPOND_STR(__to, _to_str); \ |
664
|
|
|
|
|
|
|
trace2("==> responding state %d: %s to %s\n", \ |
665
|
|
|
|
|
|
|
c->fd,_from_str,_to_str); \ |
666
|
|
|
|
|
|
|
c->responding = __to; \ |
667
|
|
|
|
|
|
|
} \ |
668
|
|
|
|
|
|
|
} while (0) |
669
|
|
|
|
|
|
|
# define change_receiving_state(c, _to) do { \ |
670
|
|
|
|
|
|
|
enum feer_receive_state __to = (_to); \ |
671
|
|
|
|
|
|
|
enum feer_receive_state __from = c->receiving; \ |
672
|
|
|
|
|
|
|
const char *_from_str, *_to_str; \ |
673
|
|
|
|
|
|
|
if (likely(__from != __to)) { \ |
674
|
|
|
|
|
|
|
RECEIVE_STR(c->receiving, _from_str); \ |
675
|
|
|
|
|
|
|
RECEIVE_STR(__to, _to_str); \ |
676
|
|
|
|
|
|
|
trace2("==> receiving state %d: %s to %s\n", \ |
677
|
|
|
|
|
|
|
c->fd,_from_str,_to_str); \ |
678
|
|
|
|
|
|
|
c->receiving = __to; \ |
679
|
|
|
|
|
|
|
} \ |
680
|
|
|
|
|
|
|
} while (0) |
681
|
|
|
|
|
|
|
#else |
682
|
|
|
|
|
|
|
# define change_responding_state(c, _to) c->responding = _to |
683
|
|
|
|
|
|
|
# define change_receiving_state(c, _to) c->receiving = _to |
684
|
|
|
|
|
|
|
#endif |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
687
|
125
|
|
|
|
|
|
start_read_watcher(struct feer_conn *c) { |
688
|
125
|
100
|
|
|
|
|
if (unlikely(ev_is_active(&c->read_ev_io))) |
689
|
7
|
|
|
|
|
|
return; |
690
|
|
|
|
|
|
|
trace("start read watcher %d\n",c->fd); |
691
|
118
|
|
|
|
|
|
ev_io_start(feersum_ev_loop, &c->read_ev_io); |
692
|
118
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
696
|
131
|
|
|
|
|
|
stop_read_watcher(struct feer_conn *c) { |
697
|
131
|
100
|
|
|
|
|
if (unlikely(!ev_is_active(&c->read_ev_io))) |
698
|
13
|
|
|
|
|
|
return; |
699
|
|
|
|
|
|
|
trace("stop read watcher %d\n",c->fd); |
700
|
118
|
|
|
|
|
|
ev_io_stop(feersum_ev_loop, &c->read_ev_io); |
701
|
118
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
705
|
124
|
|
|
|
|
|
restart_read_timer(struct feer_conn *c) { |
706
|
124
|
100
|
|
|
|
|
if (likely(!ev_is_active(&c->read_ev_timer))) { |
707
|
|
|
|
|
|
|
trace("restart read timer %d\n",c->fd); |
708
|
118
|
|
|
|
|
|
c->read_ev_timer.repeat = read_timeout; |
709
|
118
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
710
|
|
|
|
|
|
|
} |
711
|
124
|
|
|
|
|
|
ev_timer_again(feersum_ev_loop, &c->read_ev_timer); |
712
|
124
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
715
|
131
|
|
|
|
|
|
stop_read_timer(struct feer_conn *c) { |
716
|
131
|
100
|
|
|
|
|
if (unlikely(!ev_is_active(&c->read_ev_timer))) |
717
|
13
|
|
|
|
|
|
return; |
718
|
|
|
|
|
|
|
trace("stop read timer %d\n",c->fd); |
719
|
118
|
|
|
|
|
|
ev_timer_stop(feersum_ev_loop, &c->read_ev_timer); |
720
|
118
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
724
|
164
|
|
|
|
|
|
start_write_watcher(struct feer_conn *c) { |
725
|
164
|
100
|
|
|
|
|
if (unlikely(ev_is_active(&c->write_ev_io))) |
726
|
46
|
|
|
|
|
|
return; |
727
|
|
|
|
|
|
|
trace("start write watcher %d\n",c->fd); |
728
|
118
|
|
|
|
|
|
ev_io_start(feersum_ev_loop, &c->write_ev_io); |
729
|
118
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG static void |
733
|
125
|
|
|
|
|
|
stop_write_watcher(struct feer_conn *c) { |
734
|
125
|
100
|
|
|
|
|
if (unlikely(!ev_is_active(&c->write_ev_io))) |
735
|
7
|
|
|
|
|
|
return; |
736
|
|
|
|
|
|
|
trace("stop write watcher %d\n",c->fd); |
737
|
118
|
|
|
|
|
|
ev_io_stop(feersum_ev_loop, &c->write_ev_io); |
738
|
118
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
static void |
743
|
77
|
|
|
|
|
|
process_request_ready_rinq (void) |
744
|
|
|
|
|
|
|
{ |
745
|
185
|
100
|
|
|
|
|
while (request_ready_rinq) { |
746
|
108
|
|
|
|
|
|
struct feer_conn *c = |
747
|
|
|
|
|
|
|
(struct feer_conn *)rinq_shift(&request_ready_rinq); |
748
|
|
|
|
|
|
|
//trace("rinq shifted c=%p, head=%p\n", c, request_ready_rinq); |
749
|
|
|
|
|
|
|
|
750
|
108
|
|
|
|
|
|
call_request_callback(c); |
751
|
|
|
|
|
|
|
|
752
|
108
|
100
|
|
|
|
|
if (likely(c->wbuf_rinq)) { |
753
|
|
|
|
|
|
|
// this was deferred until after the perl callback |
754
|
97
|
|
|
|
|
|
conn_write_ready(c); |
755
|
|
|
|
|
|
|
} |
756
|
108
|
|
|
|
|
|
SvREFCNT_dec(c->self); // for the rinq |
757
|
|
|
|
|
|
|
} |
758
|
77
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
static void |
761
|
28
|
|
|
|
|
|
prepare_cb (EV_P_ ev_prepare *w, int revents) |
762
|
|
|
|
|
|
|
{ |
763
|
28
|
50
|
|
|
|
|
if (unlikely(revents & EV_ERROR)) { |
764
|
0
|
|
|
|
|
|
trouble("EV error in prepare, revents=0x%08x\n", revents); |
765
|
0
|
|
|
|
|
|
ev_break(EV_A, EVBREAK_ALL); |
766
|
0
|
|
|
|
|
|
return; |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
28
|
50
|
|
|
|
|
if (!ev_is_active(&accept_w) && !shutting_down) { |
|
|
50
|
|
|
|
|
|
770
|
28
|
|
|
|
|
|
ev_io_start(EV_A, &accept_w); |
771
|
|
|
|
|
|
|
} |
772
|
28
|
|
|
|
|
|
ev_prepare_stop(EV_A, w); |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
static void |
776
|
503
|
|
|
|
|
|
check_cb (EV_P_ ev_check *w, int revents) |
777
|
|
|
|
|
|
|
{ |
778
|
503
|
50
|
|
|
|
|
if (unlikely(revents & EV_ERROR)) { |
779
|
0
|
|
|
|
|
|
trouble("EV error in check, revents=0x%08x\n", revents); |
780
|
0
|
|
|
|
|
|
ev_break(EV_A, EVBREAK_ALL); |
781
|
0
|
|
|
|
|
|
return; |
782
|
|
|
|
|
|
|
} |
783
|
|
|
|
|
|
|
trace3("check! head=%p\n", request_ready_rinq); |
784
|
503
|
100
|
|
|
|
|
if (request_ready_rinq) |
785
|
77
|
|
|
|
|
|
process_request_ready_rinq(); |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
static void |
789
|
76
|
|
|
|
|
|
idle_cb (EV_P_ ev_idle *w, int revents) |
790
|
|
|
|
|
|
|
{ |
791
|
76
|
50
|
|
|
|
|
if (unlikely(revents & EV_ERROR)) { |
792
|
0
|
|
|
|
|
|
trouble("EV error in idle, revents=0x%08x\n", revents); |
793
|
0
|
|
|
|
|
|
ev_break(EV_A, EVBREAK_ALL); |
794
|
0
|
|
|
|
|
|
return; |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
trace3("idle! head=%p\n", request_ready_rinq); |
797
|
76
|
50
|
|
|
|
|
if (request_ready_rinq) |
798
|
0
|
|
|
|
|
|
process_request_ready_rinq(); |
799
|
76
|
|
|
|
|
|
ev_idle_stop(EV_A, w); |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
static void |
803
|
156
|
|
|
|
|
|
try_conn_write(EV_P_ struct ev_io *w, int revents) |
804
|
|
|
|
|
|
|
{ |
805
|
156
|
|
|
|
|
|
dCONN; |
806
|
|
|
|
|
|
|
int i; |
807
|
|
|
|
|
|
|
struct iomatrix *m; |
808
|
|
|
|
|
|
|
|
809
|
156
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
// if it's marked writeable EV suggests we simply try write to it. |
812
|
|
|
|
|
|
|
// Otherwise it is stopped and we should ditch this connection. |
813
|
156
|
50
|
|
|
|
|
if (unlikely(revents & EV_ERROR && !(revents & EV_WRITE))) { |
|
|
0
|
|
|
|
|
|
814
|
|
|
|
|
|
|
trace("EV error on write, fd=%d revents=0x%08x\n", w->fd, revents); |
815
|
0
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
816
|
0
|
|
|
|
|
|
goto try_write_finished; |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
156
|
100
|
|
|
|
|
if (unlikely(!c->wbuf_rinq)) { |
820
|
42
|
50
|
|
|
|
|
if (unlikely(c->responding >= RESPOND_SHUTDOWN)) |
821
|
0
|
|
|
|
|
|
goto try_write_finished; |
822
|
|
|
|
|
|
|
|
823
|
42
|
50
|
|
|
|
|
if (!c->poll_write_cb) { |
824
|
|
|
|
|
|
|
// no callback and no data: wait for app to push to us. |
825
|
0
|
0
|
|
|
|
|
if (c->responding == RESPOND_STREAMING) |
826
|
0
|
|
|
|
|
|
goto try_write_paused; |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
trace("tried to write with an empty buffer %d resp=%d\n",w->fd,c->responding); |
829
|
0
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
830
|
0
|
|
|
|
|
|
goto try_write_finished; |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
|
833
|
42
|
100
|
|
|
|
|
if (c->poll_write_cb_is_io_handle) |
834
|
38
|
|
|
|
|
|
pump_io_handle(c, c->poll_write_cb); |
835
|
|
|
|
|
|
|
else |
836
|
4
|
|
|
|
|
|
call_poll_callback(c, 1); |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
// callback didn't write anything: |
839
|
42
|
50
|
|
|
|
|
if (unlikely(!c->wbuf_rinq)) goto try_write_again; |
840
|
|
|
|
|
|
|
} |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
try_write_again_immediately: |
843
|
156
|
|
|
|
|
|
m = (struct iomatrix *)c->wbuf_rinq->ref; |
844
|
|
|
|
|
|
|
#if DEBUG >= 2 |
845
|
|
|
|
|
|
|
warn("going to write to %d:\n",c->fd); |
846
|
|
|
|
|
|
|
for (i=0; i < m->count; i++) { |
847
|
|
|
|
|
|
|
fprintf(stderr,"%.*s", |
848
|
|
|
|
|
|
|
(int)m->iov[i].iov_len, (char*)m->iov[i].iov_base); |
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
#endif |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
trace("going to write %d off=%d count=%d\n", w->fd, m->offset, m->count); |
853
|
156
|
|
|
|
|
|
errno = 0; |
854
|
156
|
|
|
|
|
|
ssize_t wrote = writev(w->fd, &m->iov[m->offset], m->count - m->offset); |
855
|
|
|
|
|
|
|
trace("wrote %"Ssz_df" bytes to %d, errno=%d\n", (Ssz)wrote, w->fd, errno); |
856
|
|
|
|
|
|
|
|
857
|
156
|
50
|
|
|
|
|
if (unlikely(wrote <= 0)) { |
858
|
0
|
0
|
|
|
|
|
if (unlikely(wrote == 0)) |
859
|
0
|
|
|
|
|
|
goto try_write_again; |
860
|
0
|
0
|
|
|
|
|
if (likely(errno == EAGAIN || errno == EINTR)) |
|
|
0
|
|
|
|
|
|
861
|
|
|
|
|
|
|
goto try_write_again; |
862
|
0
|
|
|
|
|
|
perror("Feersum try_conn_write"); |
863
|
0
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
864
|
0
|
|
|
|
|
|
goto try_write_finished; |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
|
867
|
1349
|
100
|
|
|
|
|
for (i = m->offset; i < m->count && wrote > 0; i++) { |
|
|
50
|
|
|
|
|
|
868
|
1193
|
|
|
|
|
|
struct iovec *v = &m->iov[i]; |
869
|
1193
|
50
|
|
|
|
|
if (unlikely(v->iov_len > wrote)) { |
870
|
|
|
|
|
|
|
trace3("offset vector %d base=%p len=%"Sz_uf"\n", |
871
|
|
|
|
|
|
|
w->fd, v->iov_base, (Sz)v->iov_len); |
872
|
0
|
|
|
|
|
|
v->iov_base += wrote; |
873
|
0
|
|
|
|
|
|
v->iov_len -= wrote; |
874
|
|
|
|
|
|
|
// don't consume any more: |
875
|
0
|
|
|
|
|
|
wrote = 0; |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
else { |
878
|
|
|
|
|
|
|
trace3("consume vector %d base=%p len=%"Sz_uf" sv=%p\n", |
879
|
|
|
|
|
|
|
w->fd, v->iov_base, (Sz)v->iov_len, m->sv[i]); |
880
|
1193
|
|
|
|
|
|
wrote -= v->iov_len; |
881
|
1193
|
|
|
|
|
|
m->offset++; |
882
|
1193
|
100
|
|
|
|
|
if (m->sv[i]) { |
883
|
632
|
|
|
|
|
|
SvREFCNT_dec(m->sv[i]); |
884
|
632
|
|
|
|
|
|
m->sv[i] = NULL; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
|
889
|
156
|
50
|
|
|
|
|
if (likely(m->offset >= m->count)) { |
890
|
|
|
|
|
|
|
trace2("all done with iomatrix %d state=%d\n",w->fd,c->responding); |
891
|
156
|
|
|
|
|
|
rinq_shift(&c->wbuf_rinq); |
892
|
156
|
|
|
|
|
|
Safefree(m); |
893
|
156
|
50
|
|
|
|
|
if (!c->wbuf_rinq) |
894
|
156
|
|
|
|
|
|
goto try_write_finished; |
895
|
|
|
|
|
|
|
trace2("write again immediately %d state=%d\n",w->fd,c->responding); |
896
|
0
|
|
|
|
|
|
goto try_write_again_immediately; |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
// else, fallthrough: |
899
|
|
|
|
|
|
|
trace2("write fallthrough %d state=%d\n",w->fd,c->responding); |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
try_write_again: |
902
|
|
|
|
|
|
|
trace("write again %d state=%d\n",w->fd,c->responding); |
903
|
38
|
|
|
|
|
|
start_write_watcher(c); |
904
|
38
|
|
|
|
|
|
goto try_write_cleanup; |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
try_write_finished: |
907
|
|
|
|
|
|
|
// should always be responding, but just in case |
908
|
156
|
|
|
|
|
|
switch(c->responding) { |
909
|
|
|
|
|
|
|
case RESPOND_NOT_STARTED: |
910
|
|
|
|
|
|
|
// the write watcher shouldn't ever get called before starting to |
911
|
|
|
|
|
|
|
// respond. Shut it down if it does. |
912
|
|
|
|
|
|
|
trace("unexpected try_write when response not started %d\n",c->fd); |
913
|
0
|
|
|
|
|
|
goto try_write_shutdown; |
914
|
|
|
|
|
|
|
case RESPOND_NORMAL: |
915
|
0
|
|
|
|
|
|
goto try_write_shutdown; |
916
|
|
|
|
|
|
|
case RESPOND_STREAMING: |
917
|
53
|
100
|
|
|
|
|
if (c->poll_write_cb) goto try_write_again; |
918
|
15
|
|
|
|
|
|
else goto try_write_paused; |
919
|
|
|
|
|
|
|
case RESPOND_SHUTDOWN: |
920
|
103
|
|
|
|
|
|
goto try_write_shutdown; |
921
|
|
|
|
|
|
|
default: |
922
|
0
|
|
|
|
|
|
goto try_write_cleanup; |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
try_write_paused: |
926
|
|
|
|
|
|
|
trace3("write PAUSED %d, refcnt=%d, state=%d\n", c->fd, SvREFCNT(c->self), c->responding); |
927
|
15
|
|
|
|
|
|
stop_write_watcher(c); |
928
|
15
|
|
|
|
|
|
goto try_write_cleanup; |
929
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
try_write_shutdown: |
931
|
|
|
|
|
|
|
trace3("write SHUTDOWN %d, refcnt=%d, state=%d\n", c->fd, SvREFCNT(c->self), c->responding); |
932
|
103
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
933
|
103
|
|
|
|
|
|
stop_write_watcher(c); |
934
|
103
|
|
|
|
|
|
safe_close_conn(c, "close at write shutdown"); |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
try_write_cleanup: |
937
|
156
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
938
|
156
|
|
|
|
|
|
return; |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
static int |
942
|
111
|
|
|
|
|
|
try_parse_http(struct feer_conn *c, size_t last_read) |
943
|
|
|
|
|
|
|
{ |
944
|
111
|
|
|
|
|
|
struct feer_req *req = c->req; |
945
|
111
|
50
|
|
|
|
|
if (likely(!req)) { |
946
|
111
|
|
|
|
|
|
Newxz(req,1,struct feer_req); |
947
|
111
|
|
|
|
|
|
c->req = req; |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
// GH#12 - incremental parsing sets num_headers to 0 each time; force it |
951
|
|
|
|
|
|
|
// back on every invocation |
952
|
111
|
|
|
|
|
|
req->num_headers = MAX_HEADERS; |
953
|
|
|
|
|
|
|
|
954
|
111
|
|
|
|
|
|
return phr_parse_request(SvPVX(c->rbuf), SvCUR(c->rbuf), |
955
|
|
|
|
|
|
|
&req->method, &req->method_len, |
956
|
|
|
|
|
|
|
&req->path, &req->path_len, &req->minor_version, |
957
|
111
|
|
|
|
|
|
req->headers, &req->num_headers, |
958
|
111
|
|
|
|
|
|
(SvCUR(c->rbuf)-last_read)); |
959
|
|
|
|
|
|
|
} |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
static void |
962
|
123
|
|
|
|
|
|
try_conn_read(EV_P_ ev_io *w, int revents) |
963
|
|
|
|
|
|
|
{ |
964
|
123
|
|
|
|
|
|
dCONN; |
965
|
123
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
// if it's marked readable EV suggests we simply try read it. Otherwise it |
968
|
|
|
|
|
|
|
// is stopped and we should ditch this connection. |
969
|
123
|
50
|
|
|
|
|
if (unlikely(revents & EV_ERROR && !(revents & EV_READ))) { |
|
|
0
|
|
|
|
|
|
970
|
|
|
|
|
|
|
trace("EV error on read, fd=%d revents=0x%08x\n", w->fd, revents); |
971
|
0
|
|
|
|
|
|
goto try_read_error; |
972
|
|
|
|
|
|
|
} |
973
|
|
|
|
|
|
|
|
974
|
123
|
50
|
|
|
|
|
if (unlikely(c->receiving == RECEIVE_SHUTDOWN)) |
975
|
0
|
|
|
|
|
|
goto dont_read_again; |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
trace("try read %d\n",w->fd); |
978
|
|
|
|
|
|
|
|
979
|
123
|
100
|
|
|
|
|
if (likely(!c->rbuf)) { // likely = optimize for small requests |
980
|
|
|
|
|
|
|
trace("init rbuf for %d\n",w->fd); |
981
|
118
|
|
|
|
|
|
c->rbuf = newSV(READ_INIT_FACTOR*READ_BUFSZ + 1); |
982
|
118
|
|
|
|
|
|
SvPOK_on(c->rbuf); |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
|
985
|
123
|
|
|
|
|
|
ssize_t space_free = SvLEN(c->rbuf) - SvCUR(c->rbuf); |
986
|
123
|
100
|
|
|
|
|
if (unlikely(space_free < READ_BUFSZ)) { // unlikely = optimize for small |
987
|
3
|
|
|
|
|
|
size_t new_len = SvLEN(c->rbuf) + READ_GROW_FACTOR*READ_BUFSZ; |
988
|
|
|
|
|
|
|
trace("moar memory %d: %"Sz_uf" to %"Sz_uf"\n", |
989
|
|
|
|
|
|
|
w->fd, (Sz)SvLEN(c->rbuf), (Sz)new_len); |
990
|
3
|
50
|
|
|
|
|
SvGROW(c->rbuf, new_len); |
|
|
50
|
|
|
|
|
|
991
|
3
|
|
|
|
|
|
space_free += READ_GROW_FACTOR*READ_BUFSZ; |
992
|
|
|
|
|
|
|
} |
993
|
|
|
|
|
|
|
|
994
|
123
|
|
|
|
|
|
char *cur = SvPVX(c->rbuf) + SvCUR(c->rbuf); |
995
|
123
|
|
|
|
|
|
ssize_t got_n = read(w->fd, cur, space_free); |
996
|
|
|
|
|
|
|
|
997
|
123
|
100
|
|
|
|
|
if (unlikely(got_n <= 0)) { |
998
|
7
|
50
|
|
|
|
|
if (unlikely(got_n == 0)) { |
999
|
|
|
|
|
|
|
trace("EOF before complete request: %d\n",w->fd,SvCUR(c->rbuf)); |
1000
|
7
|
|
|
|
|
|
goto try_read_error; |
1001
|
|
|
|
|
|
|
} |
1002
|
0
|
0
|
|
|
|
|
if (likely(errno == EAGAIN || errno == EINTR)) |
|
|
0
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
goto try_read_again; |
1004
|
0
|
|
|
|
|
|
perror("try_conn_read error"); |
1005
|
0
|
|
|
|
|
|
goto try_read_error; |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
trace("read %d %"Ssz_df"\n", w->fd, (Ssz)got_n); |
1009
|
116
|
|
|
|
|
|
SvCUR(c->rbuf) += got_n; |
1010
|
|
|
|
|
|
|
// likely = optimize for small requests |
1011
|
116
|
100
|
|
|
|
|
if (likely(c->receiving == RECEIVE_HEADERS)) { |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
#ifdef FLASH_SOCKET_POLICY_SUPPORT |
1014
|
|
|
|
|
|
|
if (unlikely(*SvPVX(c->rbuf) == '<')) { |
1015
|
|
|
|
|
|
|
if (likely(SvCUR(c->rbuf) >= 22)) { // length of vvv |
1016
|
|
|
|
|
|
|
if (str_eq(SvPVX(c->rbuf), 22, "", 22)) { |
1017
|
|
|
|
|
|
|
add_const_to_wbuf(c, STR_WITH_LEN(FLASH_SOCKET_POLICY)); |
1018
|
|
|
|
|
|
|
conn_write_ready(c); |
1019
|
|
|
|
|
|
|
stop_read_watcher(c); |
1020
|
|
|
|
|
|
|
stop_read_timer(c); |
1021
|
|
|
|
|
|
|
// TODO: keep-alives: be sure to remove the 22 bytes |
1022
|
|
|
|
|
|
|
// out of the rbuf |
1023
|
|
|
|
|
|
|
change_receiving_state(c, RECEIVE_SHUTDOWN); |
1024
|
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
1025
|
|
|
|
|
|
|
goto dont_read_again; |
1026
|
|
|
|
|
|
|
} |
1027
|
|
|
|
|
|
|
} |
1028
|
|
|
|
|
|
|
// "if prefixed with" |
1029
|
|
|
|
|
|
|
else if (likely(str_eq(SvPVX(c->rbuf), SvCUR(c->rbuf), |
1030
|
|
|
|
|
|
|
"", SvCUR(c->rbuf)))) |
1031
|
|
|
|
|
|
|
{ |
1032
|
|
|
|
|
|
|
goto try_read_again; |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
} |
1035
|
|
|
|
|
|
|
#endif |
1036
|
|
|
|
|
|
|
|
1037
|
111
|
|
|
|
|
|
int ret = try_parse_http(c, (size_t)got_n); |
1038
|
111
|
100
|
|
|
|
|
if (ret == -1) goto try_read_bad; |
1039
|
110
|
100
|
|
|
|
|
if (ret == -2) goto try_read_again; |
1040
|
|
|
|
|
|
|
|
1041
|
109
|
100
|
|
|
|
|
if (process_request_headers(c, ret)) |
1042
|
4
|
|
|
|
|
|
goto try_read_again_reset_timer; |
1043
|
|
|
|
|
|
|
else |
1044
|
105
|
|
|
|
|
|
goto dont_read_again; |
1045
|
|
|
|
|
|
|
} |
1046
|
5
|
50
|
|
|
|
|
else if (likely(c->receiving == RECEIVE_BODY)) { |
1047
|
5
|
|
|
|
|
|
c->received_cl += got_n; |
1048
|
5
|
100
|
|
|
|
|
if (c->received_cl < c->expected_cl) |
1049
|
2
|
|
|
|
|
|
goto try_read_again_reset_timer; |
1050
|
|
|
|
|
|
|
// body is complete |
1051
|
3
|
|
|
|
|
|
sched_request_callback(c); |
1052
|
3
|
|
|
|
|
|
goto dont_read_again; |
1053
|
|
|
|
|
|
|
} |
1054
|
|
|
|
|
|
|
else { |
1055
|
0
|
|
|
|
|
|
trouble("unknown read state %d %d", w->fd, c->receiving); |
1056
|
|
|
|
|
|
|
} |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
// fallthrough: |
1059
|
|
|
|
|
|
|
try_read_error: |
1060
|
|
|
|
|
|
|
trace("READ ERROR %d, refcnt=%d\n", w->fd, SvREFCNT(c->self)); |
1061
|
7
|
|
|
|
|
|
change_receiving_state(c, RECEIVE_SHUTDOWN); |
1062
|
7
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
1063
|
7
|
|
|
|
|
|
stop_read_watcher(c); |
1064
|
7
|
|
|
|
|
|
stop_read_timer(c); |
1065
|
7
|
|
|
|
|
|
stop_write_watcher(c); |
1066
|
7
|
|
|
|
|
|
goto try_read_cleanup; |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
try_read_bad: |
1069
|
|
|
|
|
|
|
trace("bad request %d\n", w->fd); |
1070
|
1
|
|
|
|
|
|
respond_with_server_error(c, "Malformed request.\n", 0, 400); |
1071
|
|
|
|
|
|
|
// TODO: when keep-alive, close conn instead of fallthrough here. |
1072
|
|
|
|
|
|
|
// fallthrough: |
1073
|
|
|
|
|
|
|
dont_read_again: |
1074
|
|
|
|
|
|
|
trace("done reading %d\n", w->fd); |
1075
|
109
|
|
|
|
|
|
change_receiving_state(c, RECEIVE_SHUTDOWN); |
1076
|
109
|
|
|
|
|
|
stop_read_watcher(c); |
1077
|
109
|
|
|
|
|
|
stop_read_timer(c); |
1078
|
109
|
|
|
|
|
|
goto try_read_cleanup; |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
try_read_again_reset_timer: |
1081
|
|
|
|
|
|
|
trace("(reset read timer) %d\n", w->fd); |
1082
|
6
|
|
|
|
|
|
restart_read_timer(c); |
1083
|
|
|
|
|
|
|
// fallthrough: |
1084
|
|
|
|
|
|
|
try_read_again: |
1085
|
|
|
|
|
|
|
trace("read again %d\n", w->fd); |
1086
|
7
|
|
|
|
|
|
start_read_watcher(c); |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
try_read_cleanup: |
1089
|
123
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
1090
|
123
|
|
|
|
|
|
} |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
static void |
1093
|
2
|
|
|
|
|
|
conn_read_timeout (EV_P_ ev_timer *w, int revents) |
1094
|
|
|
|
|
|
|
{ |
1095
|
2
|
|
|
|
|
|
dCONN; |
1096
|
2
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
1097
|
|
|
|
|
|
|
|
1098
|
2
|
50
|
|
|
|
|
if (unlikely(!(revents & EV_TIMER) || c->receiving == RECEIVE_SHUTDOWN)) { |
|
|
50
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
// if there's no EV_TIMER then EV has stopped it on an error |
1100
|
0
|
0
|
|
|
|
|
if (revents & EV_ERROR) |
1101
|
0
|
|
|
|
|
|
trouble("EV error on read timer, fd=%d revents=0x%08x\n", |
1102
|
|
|
|
|
|
|
c->fd,revents); |
1103
|
0
|
|
|
|
|
|
goto read_timeout_cleanup; |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
trace("read timeout %d\n", c->fd); |
1107
|
|
|
|
|
|
|
|
1108
|
2
|
50
|
|
|
|
|
if (likely(c->responding == RESPOND_NOT_STARTED)) { |
1109
|
|
|
|
|
|
|
const char *msg; |
1110
|
2
|
100
|
|
|
|
|
if (c->receiving == RECEIVE_HEADERS) { |
1111
|
1
|
|
|
|
|
|
msg = "Headers took too long."; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
else { |
1114
|
1
|
|
|
|
|
|
msg = "Timeout reading body."; |
1115
|
|
|
|
|
|
|
} |
1116
|
2
|
|
|
|
|
|
respond_with_server_error(c, msg, 0, 408); |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
else { |
1119
|
|
|
|
|
|
|
// XXX as of 0.984 this appears to be dead code |
1120
|
|
|
|
|
|
|
trace("read timeout while writing %d\n",c->fd); |
1121
|
0
|
|
|
|
|
|
stop_write_watcher(c); |
1122
|
0
|
|
|
|
|
|
stop_read_watcher(c); |
1123
|
0
|
|
|
|
|
|
stop_read_timer(c); |
1124
|
0
|
|
|
|
|
|
safe_close_conn(c, "close at read timeout"); |
1125
|
0
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
1126
|
|
|
|
|
|
|
} |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
read_timeout_cleanup: |
1129
|
2
|
|
|
|
|
|
stop_read_watcher(c); |
1130
|
2
|
|
|
|
|
|
stop_read_timer(c); |
1131
|
2
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
1132
|
2
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
static void |
1135
|
86
|
|
|
|
|
|
accept_cb (EV_P_ ev_io *w, int revents) |
1136
|
|
|
|
|
|
|
{ |
1137
|
|
|
|
|
|
|
struct sockaddr_storage sa_buf; |
1138
|
|
|
|
|
|
|
socklen_t sa_len; |
1139
|
|
|
|
|
|
|
|
1140
|
86
|
50
|
|
|
|
|
if (unlikely(shutting_down)) { |
1141
|
|
|
|
|
|
|
// shouldn't get called, but be defensive |
1142
|
0
|
|
|
|
|
|
ev_io_stop(EV_A, w); |
1143
|
0
|
|
|
|
|
|
close(w->fd); |
1144
|
0
|
|
|
|
|
|
return; |
1145
|
|
|
|
|
|
|
} |
1146
|
|
|
|
|
|
|
|
1147
|
86
|
50
|
|
|
|
|
if (unlikely(revents & EV_ERROR)) { |
1148
|
0
|
|
|
|
|
|
trouble("EV error in accept_cb, fd=%d, revents=0x%08x\n",w->fd,revents); |
1149
|
0
|
|
|
|
|
|
ev_break(EV_A, EVBREAK_ALL); |
1150
|
0
|
|
|
|
|
|
return; |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
trace2("accept! revents=0x%08x\n", revents); |
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
while (1) { |
1156
|
204
|
|
|
|
|
|
sa_len = sizeof(struct sockaddr_storage); |
1157
|
204
|
|
|
|
|
|
errno = 0; |
1158
|
|
|
|
|
|
|
|
1159
|
204
|
|
|
|
|
|
int fd = accept(w->fd, (struct sockaddr *)&sa_buf, &sa_len); |
1160
|
|
|
|
|
|
|
trace("accepted fd=%d, errno=%d\n", fd, errno); |
1161
|
204
|
100
|
|
|
|
|
if (fd == -1) break; |
1162
|
|
|
|
|
|
|
|
1163
|
118
|
|
|
|
|
|
int is_tcp = 1; |
1164
|
|
|
|
|
|
|
#ifdef AF_UNIX |
1165
|
118
|
50
|
|
|
|
|
if (unlikely(sa_buf.ss_family == AF_UNIX)) is_tcp = 0; |
1166
|
|
|
|
|
|
|
#endif |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
assert(sa_len <= sizeof(struct sockaddr_storage)); |
1169
|
118
|
50
|
|
|
|
|
if (unlikely(prep_socket(fd, is_tcp))) { |
1170
|
0
|
|
|
|
|
|
perror("prep_socket"); |
1171
|
0
|
|
|
|
|
|
trouble("prep_socket failed for %d\n", fd); |
1172
|
0
|
|
|
|
|
|
close(fd); |
1173
|
0
|
|
|
|
|
|
continue; |
1174
|
|
|
|
|
|
|
} |
1175
|
|
|
|
|
|
|
|
1176
|
118
|
|
|
|
|
|
struct sockaddr *sa = (struct sockaddr *)malloc(sa_len); |
1177
|
118
|
|
|
|
|
|
memcpy(sa,&sa_buf,(size_t)sa_len); |
1178
|
118
|
|
|
|
|
|
struct feer_conn *c = new_feer_conn(EV_A,fd,sa); |
1179
|
118
|
|
|
|
|
|
start_read_watcher(c); |
1180
|
118
|
|
|
|
|
|
restart_read_timer(c); |
1181
|
|
|
|
|
|
|
assert(SvREFCNT(c->self) == 3); |
1182
|
118
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
1183
|
204
|
|
|
|
|
|
} |
1184
|
|
|
|
|
|
|
} |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
static void |
1187
|
108
|
|
|
|
|
|
sched_request_callback (struct feer_conn *c) |
1188
|
|
|
|
|
|
|
{ |
1189
|
|
|
|
|
|
|
trace("sched req callback: %d c=%p, head=%p\n", c->fd, c, request_ready_rinq); |
1190
|
108
|
|
|
|
|
|
rinq_push(&request_ready_rinq, c); |
1191
|
108
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); // for the rinq |
1192
|
108
|
100
|
|
|
|
|
if (!ev_is_active(&ei)) { |
1193
|
77
|
|
|
|
|
|
ev_idle_start(feersum_ev_loop, &ei); |
1194
|
|
|
|
|
|
|
} |
1195
|
108
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
// the unlikely/likely annotations here are trying to optimize for GET first |
1198
|
|
|
|
|
|
|
// and POST second. Other entity-body requests are third in line. |
1199
|
|
|
|
|
|
|
static bool |
1200
|
109
|
|
|
|
|
|
process_request_headers (struct feer_conn *c, int body_offset) |
1201
|
|
|
|
|
|
|
{ |
1202
|
|
|
|
|
|
|
int err_code; |
1203
|
|
|
|
|
|
|
const char *err; |
1204
|
109
|
|
|
|
|
|
struct feer_req *req = c->req; |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
trace("processing headers %d minor_version=%d\n",c->fd,req->minor_version); |
1207
|
|
|
|
|
|
|
bool body_is_required; |
1208
|
109
|
|
|
|
|
|
bool next_req_follows = 0; |
1209
|
|
|
|
|
|
|
|
1210
|
109
|
|
|
|
|
|
c->is_http11 = (req->minor_version == 1); |
1211
|
|
|
|
|
|
|
|
1212
|
109
|
|
|
|
|
|
change_receiving_state(c, RECEIVE_BODY); |
1213
|
|
|
|
|
|
|
|
1214
|
109
|
100
|
|
|
|
|
if (likely(str_eq("GET", 3, req->method, req->method_len))) { |
1215
|
|
|
|
|
|
|
// Not supposed to have a body. Additional bytes are either a |
1216
|
|
|
|
|
|
|
// mistake, a websocket negotiation or pipelined requests under |
1217
|
|
|
|
|
|
|
// HTTP/1.1 |
1218
|
98
|
|
|
|
|
|
next_req_follows = 1; |
1219
|
|
|
|
|
|
|
} |
1220
|
11
|
50
|
|
|
|
|
else if (likely(str_eq("OPTIONS", 7, req->method, req->method_len))) { |
1221
|
0
|
|
|
|
|
|
body_is_required = 1; |
1222
|
0
|
|
|
|
|
|
next_req_follows = 1; |
1223
|
|
|
|
|
|
|
} |
1224
|
11
|
50
|
|
|
|
|
else if (likely(str_eq("POST", 4, req->method, req->method_len))) { |
1225
|
11
|
|
|
|
|
|
body_is_required = 1; |
1226
|
|
|
|
|
|
|
} |
1227
|
0
|
0
|
|
|
|
|
else if (str_eq("PUT", 3, req->method, req->method_len)) { |
1228
|
0
|
|
|
|
|
|
body_is_required = 1; |
1229
|
|
|
|
|
|
|
} |
1230
|
0
|
|
|
|
|
|
else if (str_eq("HEAD", 4, req->method, req->method_len) || |
1231
|
0
|
|
|
|
|
|
str_eq("DELETE", 6, req->method, req->method_len)) |
1232
|
|
|
|
|
|
|
{ |
1233
|
0
|
|
|
|
|
|
next_req_follows = 1; |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
else { |
1236
|
0
|
|
|
|
|
|
err = "Feersum doesn't support that method yet\n"; |
1237
|
0
|
|
|
|
|
|
err_code = 405; |
1238
|
0
|
|
|
|
|
|
goto got_bad_request; |
1239
|
|
|
|
|
|
|
} |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
#if DEBUG >= 2 |
1242
|
|
|
|
|
|
|
if (next_req_follows) |
1243
|
|
|
|
|
|
|
trace2("next req follows fd=%d, boff=%d\n",c->fd,body_offset); |
1244
|
|
|
|
|
|
|
if (body_is_required) |
1245
|
|
|
|
|
|
|
trace2("body is required fd=%d, boff=%d\n",c->fd,body_offset); |
1246
|
|
|
|
|
|
|
#endif |
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
// a body or follow-on data potentially follows the headers. Let feer_req |
1249
|
|
|
|
|
|
|
// retain its pointers into rbuf and make a new scalar for more body data. |
1250
|
|
|
|
|
|
|
STRLEN from_len; |
1251
|
109
|
50
|
|
|
|
|
char *from = SvPV(c->rbuf,from_len); |
1252
|
109
|
|
|
|
|
|
from += body_offset; |
1253
|
109
|
|
|
|
|
|
int need = from_len - body_offset; |
1254
|
109
|
|
|
|
|
|
int new_alloc = (need > READ_INIT_FACTOR*READ_BUFSZ) |
1255
|
109
|
50
|
|
|
|
|
? need : READ_INIT_FACTOR*READ_BUFSZ-1; |
1256
|
|
|
|
|
|
|
trace("new rbuf for body %d need=%d alloc=%d\n",c->fd, need, new_alloc); |
1257
|
109
|
100
|
|
|
|
|
SV *new_rbuf = newSVpvn(need ? from : "", need); |
1258
|
|
|
|
|
|
|
|
1259
|
109
|
|
|
|
|
|
req->buf = c->rbuf; |
1260
|
109
|
|
|
|
|
|
c->rbuf = new_rbuf; |
1261
|
109
|
|
|
|
|
|
SvCUR_set(req->buf, body_offset); |
1262
|
|
|
|
|
|
|
|
1263
|
109
|
100
|
|
|
|
|
if (likely(next_req_follows)) // optimize for GET |
1264
|
98
|
|
|
|
|
|
goto got_it_all; |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
// determine how much we need to read |
1267
|
|
|
|
|
|
|
int i; |
1268
|
11
|
|
|
|
|
|
UV expected = 0; |
1269
|
27
|
50
|
|
|
|
|
for (i=0; i < req->num_headers; i++) { |
1270
|
27
|
|
|
|
|
|
struct phr_header *hdr = &req->headers[i]; |
1271
|
27
|
50
|
|
|
|
|
if (!hdr->name) continue; |
1272
|
|
|
|
|
|
|
// XXX: ignore multiple C-L headers? |
1273
|
27
|
100
|
|
|
|
|
if (unlikely( |
1274
|
|
|
|
|
|
|
str_case_eq("content-length", 14, hdr->name, hdr->name_len))) |
1275
|
|
|
|
|
|
|
{ |
1276
|
11
|
|
|
|
|
|
int g = grok_number(hdr->value, hdr->value_len, &expected); |
1277
|
11
|
50
|
|
|
|
|
if (likely(g == IS_NUMBER_IN_UV)) { |
1278
|
11
|
50
|
|
|
|
|
if (unlikely(expected > MAX_BODY_LEN)) { |
1279
|
0
|
|
|
|
|
|
err_code = 413; |
1280
|
0
|
|
|
|
|
|
err = "Content length exceeds maximum\n"; |
1281
|
0
|
|
|
|
|
|
goto got_bad_request; |
1282
|
|
|
|
|
|
|
} |
1283
|
|
|
|
|
|
|
else |
1284
|
11
|
|
|
|
|
|
goto got_cl; |
1285
|
|
|
|
|
|
|
} |
1286
|
|
|
|
|
|
|
else { |
1287
|
0
|
|
|
|
|
|
err_code = 400; |
1288
|
0
|
|
|
|
|
|
err = "invalid content-length\n"; |
1289
|
0
|
|
|
|
|
|
goto got_bad_request; |
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
} |
1292
|
|
|
|
|
|
|
// TODO: support "Connection: close" bodies |
1293
|
|
|
|
|
|
|
// TODO: support "Transfer-Encoding: chunked" bodies |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
|
1296
|
0
|
0
|
|
|
|
|
if (body_is_required) { |
1297
|
|
|
|
|
|
|
// Go the nginx route... |
1298
|
0
|
|
|
|
|
|
err_code = 411; |
1299
|
0
|
|
|
|
|
|
err = "Content-Length required\n"; |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
else { |
1302
|
|
|
|
|
|
|
// XXX TODO support requests that don't require a body |
1303
|
0
|
|
|
|
|
|
err_code = 418; |
1304
|
0
|
|
|
|
|
|
err = "Feersum doesn't know how to handle optional-body requests yet\n"; |
1305
|
|
|
|
|
|
|
} |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
got_bad_request: |
1308
|
0
|
|
|
|
|
|
respond_with_server_error(c, err, 0, err_code); |
1309
|
0
|
|
|
|
|
|
return 0; |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
got_cl: |
1312
|
11
|
|
|
|
|
|
c->expected_cl = (ssize_t)expected; |
1313
|
11
|
|
|
|
|
|
c->received_cl = SvCUR(c->rbuf); |
1314
|
|
|
|
|
|
|
trace("expecting body %d size=%"Ssz_df" have=%"Ssz_df"\n", |
1315
|
|
|
|
|
|
|
c->fd, (Ssz)c->expected_cl, (Ssz)c->received_cl); |
1316
|
11
|
50
|
|
|
|
|
SvGROW(c->rbuf, c->expected_cl + 1); |
|
|
100
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
// don't have enough bytes to schedule immediately? |
1319
|
|
|
|
|
|
|
// unlikely = optimize for short requests |
1320
|
11
|
100
|
|
|
|
|
if (unlikely(c->expected_cl && c->received_cl < c->expected_cl)) { |
|
|
100
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
// TODO: schedule the callback immediately and support a non-blocking |
1322
|
|
|
|
|
|
|
// ->read method. |
1323
|
|
|
|
|
|
|
// sched_request_callback(c); |
1324
|
|
|
|
|
|
|
// change_receiving_state(c, RECEIVE_STREAM); |
1325
|
4
|
|
|
|
|
|
return 1; |
1326
|
|
|
|
|
|
|
} |
1327
|
|
|
|
|
|
|
// fallthrough: have enough bytes |
1328
|
|
|
|
|
|
|
got_it_all: |
1329
|
105
|
|
|
|
|
|
sched_request_callback(c); |
1330
|
109
|
|
|
|
|
|
return 0; |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
static void |
1334
|
328
|
|
|
|
|
|
conn_write_ready (struct feer_conn *c) |
1335
|
|
|
|
|
|
|
{ |
1336
|
328
|
100
|
|
|
|
|
if (c->in_callback) return; // defer until out of callback |
1337
|
|
|
|
|
|
|
|
1338
|
126
|
100
|
|
|
|
|
if (c->write_ev_io.data == NULL) { |
1339
|
103
|
|
|
|
|
|
ev_io_init(&c->write_ev_io, try_conn_write, c->fd, EV_WRITE); |
1340
|
103
|
|
|
|
|
|
c->write_ev_io.data = (void *)c; |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
#if AUTOCORK_WRITES |
1344
|
126
|
|
|
|
|
|
start_write_watcher(c); |
1345
|
|
|
|
|
|
|
#else |
1346
|
|
|
|
|
|
|
// attempt a non-blocking write immediately if we're not already |
1347
|
|
|
|
|
|
|
// waiting for writability |
1348
|
|
|
|
|
|
|
try_conn_write(feersum_ev_loop, &c->write_ev_io, EV_WRITE); |
1349
|
|
|
|
|
|
|
#endif |
1350
|
|
|
|
|
|
|
} |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
static void |
1353
|
5
|
|
|
|
|
|
respond_with_server_error (struct feer_conn *c, const char *msg, STRLEN msg_len, int err_code) |
1354
|
|
|
|
|
|
|
{ |
1355
|
|
|
|
|
|
|
SV *tmp; |
1356
|
|
|
|
|
|
|
|
1357
|
5
|
50
|
|
|
|
|
if (unlikely(c->responding != RESPOND_NOT_STARTED)) { |
1358
|
0
|
|
|
|
|
|
trouble("Tried to send server error but already responding!"); |
1359
|
0
|
|
|
|
|
|
return; |
1360
|
|
|
|
|
|
|
} |
1361
|
|
|
|
|
|
|
|
1362
|
5
|
50
|
|
|
|
|
if (!msg_len) msg_len = strlen(msg); |
1363
|
|
|
|
|
|
|
assert(msg_len < INT_MAX); |
1364
|
|
|
|
|
|
|
|
1365
|
5
|
|
|
|
|
|
tmp = newSVpvf("HTTP/1.%d %d %s" CRLF |
1366
|
|
|
|
|
|
|
"Content-Type: text/plain" CRLF |
1367
|
|
|
|
|
|
|
"Connection: close" CRLF |
1368
|
|
|
|
|
|
|
"Cache-Control: no-cache, no-store" CRLF |
1369
|
|
|
|
|
|
|
"Content-Length: %"Ssz_df"" CRLFx2 |
1370
|
|
|
|
|
|
|
"%.*s", |
1371
|
5
|
|
|
|
|
|
c->is_http11 ? 1 : 0, |
1372
|
|
|
|
|
|
|
err_code, http_code_to_msg(err_code), |
1373
|
|
|
|
|
|
|
(Ssz)msg_len, |
1374
|
|
|
|
|
|
|
(int)msg_len, msg); |
1375
|
5
|
|
|
|
|
|
add_sv_to_wbuf(c, sv_2mortal(tmp)); |
1376
|
|
|
|
|
|
|
|
1377
|
5
|
|
|
|
|
|
stop_read_watcher(c); |
1378
|
5
|
|
|
|
|
|
stop_read_timer(c); |
1379
|
5
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
1380
|
5
|
|
|
|
|
|
change_receiving_state(c, RECEIVE_SHUTDOWN); |
1381
|
5
|
|
|
|
|
|
conn_write_ready(c); |
1382
|
|
|
|
|
|
|
} |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG bool |
1385
|
131
|
|
|
|
|
|
str_eq(const char *a, int a_len, const char *b, int b_len) |
1386
|
|
|
|
|
|
|
{ |
1387
|
131
|
100
|
|
|
|
|
if (a_len != b_len) return 0; |
1388
|
109
|
50
|
|
|
|
|
if (a == b) return 1; |
1389
|
|
|
|
|
|
|
int i; |
1390
|
447
|
100
|
|
|
|
|
for (i=0; i
|
|
|
50
|
|
|
|
|
|
1391
|
338
|
50
|
|
|
|
|
if (a[i] != b[i]) return 0; |
1392
|
|
|
|
|
|
|
} |
1393
|
109
|
|
|
|
|
|
return 1; |
1394
|
|
|
|
|
|
|
} |
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
/* |
1397
|
|
|
|
|
|
|
* Compares two strings, assumes that the first string is already lower-cased |
1398
|
|
|
|
|
|
|
*/ |
1399
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG bool |
1400
|
853
|
|
|
|
|
|
str_case_eq(const char *a, int a_len, const char *b, int b_len) |
1401
|
|
|
|
|
|
|
{ |
1402
|
853
|
100
|
|
|
|
|
if (a_len != b_len) return 0; |
1403
|
79
|
50
|
|
|
|
|
if (a == b) return 1; |
1404
|
|
|
|
|
|
|
int i; |
1405
|
605
|
100
|
|
|
|
|
for (i=0; i
|
|
|
50
|
|
|
|
|
|
1406
|
566
|
100
|
|
|
|
|
if (a[i] != tolower(b[i])) return 0; |
1407
|
|
|
|
|
|
|
} |
1408
|
39
|
|
|
|
|
|
return 1; |
1409
|
|
|
|
|
|
|
} |
1410
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
INLINE_UNLESS_DEBUG int |
1412
|
32
|
|
|
|
|
|
hex_decode(const char ch) |
1413
|
|
|
|
|
|
|
{ |
1414
|
32
|
100
|
|
|
|
|
if (likely('0' <= ch && ch <= '9')) |
|
|
100
|
|
|
|
|
|
1415
|
26
|
|
|
|
|
|
return ch - '0'; |
1416
|
6
|
100
|
|
|
|
|
else if ('A' <= ch && ch <= 'F') |
|
|
100
|
|
|
|
|
|
1417
|
2
|
|
|
|
|
|
return ch - 'A' + 10; |
1418
|
4
|
100
|
|
|
|
|
else if ('a' <= ch && ch <= 'f') |
|
|
50
|
|
|
|
|
|
1419
|
2
|
|
|
|
|
|
return ch - 'a' + 10; |
1420
|
2
|
|
|
|
|
|
return -1; |
1421
|
|
|
|
|
|
|
} |
1422
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
static void |
1424
|
99
|
|
|
|
|
|
uri_decode_sv (SV *sv) |
1425
|
|
|
|
|
|
|
{ |
1426
|
|
|
|
|
|
|
STRLEN len; |
1427
|
|
|
|
|
|
|
char *ptr, *end, *decoded; |
1428
|
|
|
|
|
|
|
|
1429
|
99
|
50
|
|
|
|
|
ptr = SvPV(sv, len); |
1430
|
99
|
|
|
|
|
|
end = SvEND(sv); |
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
// quickly scan for % so we can ignore decoding that portion of the string |
1433
|
452
|
100
|
|
|
|
|
while (ptr < end) { |
1434
|
360
|
100
|
|
|
|
|
if (unlikely(*ptr == '%')) goto needs_decode; |
1435
|
353
|
|
|
|
|
|
ptr++; |
1436
|
|
|
|
|
|
|
} |
1437
|
92
|
|
|
|
|
|
return; |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
needs_decode: |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
// Up until ptr have been "decoded" already by virtue of those chars not |
1442
|
|
|
|
|
|
|
// being encoded. |
1443
|
7
|
|
|
|
|
|
decoded = ptr; |
1444
|
|
|
|
|
|
|
|
1445
|
53
|
100
|
|
|
|
|
for (; ptr < end; ptr++) { |
1446
|
46
|
100
|
|
|
|
|
if (unlikely(*ptr == '%') && likely(end - ptr >= 2)) { |
|
|
50
|
|
|
|
|
|
1447
|
16
|
|
|
|
|
|
int c1 = hex_decode(ptr[1]); |
1448
|
16
|
|
|
|
|
|
int c2 = hex_decode(ptr[2]); |
1449
|
16
|
100
|
|
|
|
|
if (likely(c1 != -1 && c2 != -1)) { |
|
|
100
|
|
|
|
|
|
1450
|
14
|
|
|
|
|
|
*decoded++ = (c1 << 4) + c2; |
1451
|
14
|
|
|
|
|
|
ptr += 2; |
1452
|
14
|
|
|
|
|
|
continue; |
1453
|
|
|
|
|
|
|
} |
1454
|
|
|
|
|
|
|
} |
1455
|
32
|
|
|
|
|
|
*decoded++ = *ptr; |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
|
1458
|
7
|
|
|
|
|
|
*decoded = '\0'; // play nice with C |
1459
|
|
|
|
|
|
|
|
1460
|
7
|
50
|
|
|
|
|
ptr = SvPV_nolen(sv); |
1461
|
7
|
|
|
|
|
|
SvCUR_set(sv, decoded-ptr); |
1462
|
|
|
|
|
|
|
} |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
static void |
1465
|
23
|
|
|
|
|
|
feersum_init_tmpl_env(pTHX) |
1466
|
|
|
|
|
|
|
{ |
1467
|
|
|
|
|
|
|
HV *e; |
1468
|
23
|
|
|
|
|
|
e = newHV(); |
1469
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
// constants |
1471
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.version", newRV((SV*)psgi_ver)); |
1472
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.url_scheme", newSVpvs("http")); |
1473
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.run_once", &PL_sv_no); |
1474
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.nonblocking", &PL_sv_yes); |
1475
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.multithread", &PL_sv_no); |
1476
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.multiprocess", &PL_sv_no); |
1477
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.streaming", &PL_sv_yes); |
1478
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.errors", newRV((SV*)PL_stderrgv)); |
1479
|
23
|
|
|
|
|
|
hv_stores(e, "psgix.input.buffered", &PL_sv_yes); |
1480
|
23
|
|
|
|
|
|
hv_stores(e, "psgix.output.buffered", &PL_sv_yes); |
1481
|
23
|
|
|
|
|
|
hv_stores(e, "psgix.body.scalar_refs", &PL_sv_yes); |
1482
|
23
|
|
|
|
|
|
hv_stores(e, "psgix.output.guard", &PL_sv_yes); |
1483
|
23
|
|
|
|
|
|
hv_stores(e, "SCRIPT_NAME", newSVpvs("")); |
1484
|
|
|
|
|
|
|
|
1485
|
|
|
|
|
|
|
// placeholders that get defined for every request |
1486
|
23
|
|
|
|
|
|
hv_stores(e, "SERVER_PROTOCOL", &PL_sv_undef); |
1487
|
23
|
|
|
|
|
|
hv_stores(e, "SERVER_NAME", &PL_sv_undef); |
1488
|
23
|
|
|
|
|
|
hv_stores(e, "SERVER_PORT", &PL_sv_undef); |
1489
|
23
|
|
|
|
|
|
hv_stores(e, "REQUEST_URI", &PL_sv_undef); |
1490
|
23
|
|
|
|
|
|
hv_stores(e, "REQUEST_METHOD", &PL_sv_undef); |
1491
|
23
|
|
|
|
|
|
hv_stores(e, "PATH_INFO", &PL_sv_undef); |
1492
|
23
|
|
|
|
|
|
hv_stores(e, "REMOTE_ADDR", &PL_sv_placeholder); |
1493
|
23
|
|
|
|
|
|
hv_stores(e, "REMOTE_PORT", &PL_sv_placeholder); |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
// defaults that get changed for some requests |
1496
|
23
|
|
|
|
|
|
hv_stores(e, "psgi.input", &PL_sv_undef); |
1497
|
23
|
|
|
|
|
|
hv_stores(e, "CONTENT_LENGTH", newSViv(0)); |
1498
|
23
|
|
|
|
|
|
hv_stores(e, "QUERY_STRING", newSVpvs("")); |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
// anticipated headers |
1501
|
23
|
|
|
|
|
|
hv_stores(e, "CONTENT_TYPE", &PL_sv_placeholder); |
1502
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_HOST", &PL_sv_placeholder); |
1503
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_USER_AGENT", &PL_sv_placeholder); |
1504
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_ACCEPT", &PL_sv_placeholder); |
1505
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_ACCEPT_LANGUAGE", &PL_sv_placeholder); |
1506
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_ACCEPT_CHARSET", &PL_sv_placeholder); |
1507
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_KEEP_ALIVE", &PL_sv_placeholder); |
1508
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_CONNECTION", &PL_sv_placeholder); |
1509
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_REFERER", &PL_sv_placeholder); |
1510
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_COOKIE", &PL_sv_placeholder); |
1511
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_IF_MODIFIED_SINCE", &PL_sv_placeholder); |
1512
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_IF_NONE_MATCH", &PL_sv_placeholder); |
1513
|
23
|
|
|
|
|
|
hv_stores(e, "HTTP_CACHE_CONTROL", &PL_sv_placeholder); |
1514
|
|
|
|
|
|
|
|
1515
|
23
|
|
|
|
|
|
hv_stores(e, "psgix.io", &PL_sv_placeholder); |
1516
|
|
|
|
|
|
|
|
1517
|
23
|
|
|
|
|
|
feersum_tmpl_env = e; |
1518
|
23
|
|
|
|
|
|
} |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
static HV* |
1521
|
99
|
|
|
|
|
|
feersum_env(pTHX_ struct feer_conn *c) |
1522
|
|
|
|
|
|
|
{ |
1523
|
|
|
|
|
|
|
HV *e; |
1524
|
|
|
|
|
|
|
SV **hsv; |
1525
|
|
|
|
|
|
|
int i,j; |
1526
|
99
|
|
|
|
|
|
struct feer_req *r = c->req; |
1527
|
|
|
|
|
|
|
|
1528
|
99
|
100
|
|
|
|
|
if (unlikely(!feersum_tmpl_env)) |
1529
|
23
|
|
|
|
|
|
feersum_init_tmpl_env(aTHX); |
1530
|
99
|
|
|
|
|
|
e = newHVhv(feersum_tmpl_env); |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
trace("generating header (fd %d) %.*s\n", |
1533
|
|
|
|
|
|
|
c->fd, (int)r->path_len, r->path); |
1534
|
|
|
|
|
|
|
|
1535
|
99
|
|
|
|
|
|
SV *path = newSVpvn(r->path, r->path_len); |
1536
|
99
|
|
|
|
|
|
hv_stores(e, "SERVER_NAME", newSVsv(feer_server_name)); |
1537
|
99
|
|
|
|
|
|
hv_stores(e, "SERVER_PORT", newSVsv(feer_server_port)); |
1538
|
99
|
|
|
|
|
|
hv_stores(e, "REQUEST_URI", path); |
1539
|
99
|
|
|
|
|
|
hv_stores(e, "REQUEST_METHOD", newSVpvn(r->method,r->method_len)); |
1540
|
99
|
100
|
|
|
|
|
hv_stores(e, "SERVER_PROTOCOL", (r->minor_version == 1) ? |
1541
|
|
|
|
|
|
|
newSVsv(psgi_serv11) : newSVsv(psgi_serv10)); |
1542
|
|
|
|
|
|
|
|
1543
|
99
|
|
|
|
|
|
SV *addr = &PL_sv_undef; |
1544
|
99
|
|
|
|
|
|
SV *port = &PL_sv_undef; |
1545
|
|
|
|
|
|
|
const char *str_addr; |
1546
|
|
|
|
|
|
|
unsigned short s_port; |
1547
|
|
|
|
|
|
|
|
1548
|
99
|
50
|
|
|
|
|
if (c->sa->sa_family == AF_INET) { |
1549
|
99
|
|
|
|
|
|
struct sockaddr_in *in = (struct sockaddr_in *)c->sa; |
1550
|
99
|
|
|
|
|
|
addr = newSV(INET_ADDRSTRLEN); |
1551
|
99
|
|
|
|
|
|
str_addr = inet_ntop(AF_INET,&in->sin_addr,SvPVX(addr),INET_ADDRSTRLEN); |
1552
|
99
|
|
|
|
|
|
s_port = ntohs(in->sin_port); |
1553
|
|
|
|
|
|
|
} |
1554
|
|
|
|
|
|
|
#ifdef AF_INET6 |
1555
|
0
|
0
|
|
|
|
|
else if (c->sa->sa_family == AF_INET6) { |
1556
|
0
|
|
|
|
|
|
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)c->sa; |
1557
|
0
|
|
|
|
|
|
addr = newSV(INET6_ADDRSTRLEN); |
1558
|
0
|
|
|
|
|
|
str_addr = inet_ntop(AF_INET6,&in6->sin6_addr,SvPVX(addr),INET6_ADDRSTRLEN); |
1559
|
0
|
|
|
|
|
|
s_port = ntohs(in6->sin6_port); |
1560
|
|
|
|
|
|
|
} |
1561
|
|
|
|
|
|
|
#endif |
1562
|
|
|
|
|
|
|
#ifdef AF_UNIX |
1563
|
0
|
0
|
|
|
|
|
else if (c->sa->sa_family == AF_UNIX) { |
1564
|
0
|
|
|
|
|
|
str_addr = "unix"; |
1565
|
0
|
|
|
|
|
|
addr = newSV(sizeof(str_addr)); |
1566
|
0
|
|
|
|
|
|
memcpy(SvPVX(addr), str_addr, sizeof(str_addr)); |
1567
|
0
|
|
|
|
|
|
s_port = 0; |
1568
|
|
|
|
|
|
|
} |
1569
|
|
|
|
|
|
|
#endif |
1570
|
|
|
|
|
|
|
|
1571
|
99
|
50
|
|
|
|
|
if (likely(str_addr)) { |
1572
|
99
|
|
|
|
|
|
SvCUR(addr) = strlen(SvPVX(addr)); |
1573
|
99
|
|
|
|
|
|
SvPOK_on(addr); |
1574
|
99
|
|
|
|
|
|
port = newSViv(s_port); |
1575
|
|
|
|
|
|
|
} |
1576
|
99
|
|
|
|
|
|
hv_stores(e, "REMOTE_ADDR", addr); |
1577
|
99
|
|
|
|
|
|
hv_stores(e, "REMOTE_PORT", port); |
1578
|
|
|
|
|
|
|
|
1579
|
99
|
100
|
|
|
|
|
if (unlikely(c->expected_cl > 0)) { |
1580
|
9
|
|
|
|
|
|
hv_stores(e, "CONTENT_LENGTH", newSViv(c->expected_cl)); |
1581
|
9
|
|
|
|
|
|
hv_stores(e, "psgi.input", new_feer_conn_handle(aTHX_ c,0)); |
1582
|
|
|
|
|
|
|
} |
1583
|
90
|
|
|
|
|
|
else if (request_cb_is_psgi) { |
1584
|
|
|
|
|
|
|
// TODO: make psgi.input a valid, but always empty stream for PSGI mode? |
1585
|
|
|
|
|
|
|
} |
1586
|
|
|
|
|
|
|
|
1587
|
99
|
100
|
|
|
|
|
if (request_cb_is_psgi) { |
1588
|
73
|
|
|
|
|
|
SV *fake_fh = newSViv(c->fd); // just some random dummy value |
1589
|
73
|
|
|
|
|
|
SV *selfref = sv_2mortal(feer_conn_2sv(c)); |
1590
|
73
|
|
|
|
|
|
sv_magicext(fake_fh, selfref, PERL_MAGIC_ext, &psgix_io_vtbl, NULL, 0); |
1591
|
73
|
|
|
|
|
|
hv_stores(e, "psgix.io", fake_fh); |
1592
|
|
|
|
|
|
|
} |
1593
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
{ |
1595
|
99
|
|
|
|
|
|
const char *qpos = r->path; |
1596
|
|
|
|
|
|
|
SV *pinfo, *qstr; |
1597
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
// rather than memchr, for speed: |
1599
|
526
|
100
|
|
|
|
|
while (*qpos != '?' && qpos < r->path + r->path_len) |
|
|
100
|
|
|
|
|
|
1600
|
427
|
|
|
|
|
|
qpos++; |
1601
|
|
|
|
|
|
|
|
1602
|
99
|
100
|
|
|
|
|
if (*qpos == '?') { |
1603
|
16
|
|
|
|
|
|
pinfo = newSVpvn(r->path, (qpos - r->path)); |
1604
|
16
|
|
|
|
|
|
qpos++; |
1605
|
16
|
|
|
|
|
|
qstr = newSVpvn(qpos, r->path_len - (qpos - r->path)); |
1606
|
|
|
|
|
|
|
} |
1607
|
|
|
|
|
|
|
else { |
1608
|
83
|
|
|
|
|
|
pinfo = newSVsv(path); |
1609
|
83
|
|
|
|
|
|
qstr = NULL; // use template default |
1610
|
|
|
|
|
|
|
} |
1611
|
99
|
|
|
|
|
|
uri_decode_sv(pinfo); |
1612
|
99
|
|
|
|
|
|
hv_stores(e, "PATH_INFO", pinfo); |
1613
|
99
|
100
|
|
|
|
|
if (qstr != NULL) // hv template defaults QUERY_STRING to empty |
1614
|
16
|
|
|
|
|
|
hv_stores(e, "QUERY_STRING", qstr); |
1615
|
|
|
|
|
|
|
} |
1616
|
|
|
|
|
|
|
|
1617
|
99
|
|
|
|
|
|
SV *val = NULL; |
1618
|
|
|
|
|
|
|
char *kbuf; |
1619
|
99
|
|
|
|
|
|
size_t kbuflen = 64; |
1620
|
99
|
|
|
|
|
|
Newx(kbuf, kbuflen, char); |
1621
|
99
|
|
|
|
|
|
kbuf[0]='H'; kbuf[1]='T'; kbuf[2]='T'; kbuf[3]='P'; kbuf[4]='_'; |
1622
|
|
|
|
|
|
|
|
1623
|
448
|
100
|
|
|
|
|
for (i=0; inum_headers; i++) { |
1624
|
349
|
|
|
|
|
|
struct phr_header *hdr = &(r->headers[i]); |
1625
|
349
|
50
|
|
|
|
|
if (unlikely(hdr->name == NULL && val != NULL)) { |
|
|
0
|
|
|
|
|
|
1626
|
|
|
|
|
|
|
trace("... multiline %.*s\n", (int)hdr->value_len, hdr->value); |
1627
|
0
|
|
|
|
|
|
sv_catpvn(val, hdr->value, hdr->value_len); |
1628
|
0
|
|
|
|
|
|
continue; |
1629
|
|
|
|
|
|
|
} |
1630
|
349
|
100
|
|
|
|
|
else if (unlikely(str_case_eq( |
1631
|
|
|
|
|
|
|
STR_WITH_LEN("content-length"), hdr->name, hdr->name_len))) |
1632
|
|
|
|
|
|
|
{ |
1633
|
|
|
|
|
|
|
// content length shouldn't show up as HTTP_CONTENT_LENGTH but |
1634
|
|
|
|
|
|
|
// as CONTENT_LENGTH in the env-hash. |
1635
|
10
|
|
|
|
|
|
continue; |
1636
|
|
|
|
|
|
|
} |
1637
|
339
|
100
|
|
|
|
|
else if (unlikely(str_case_eq( |
1638
|
|
|
|
|
|
|
STR_WITH_LEN("content-type"), hdr->name, hdr->name_len))) |
1639
|
|
|
|
|
|
|
{ |
1640
|
10
|
|
|
|
|
|
hv_stores(e, "CONTENT_TYPE",newSVpvn(hdr->value, hdr->value_len)); |
1641
|
10
|
|
|
|
|
|
continue; |
1642
|
|
|
|
|
|
|
} |
1643
|
|
|
|
|
|
|
|
1644
|
329
|
|
|
|
|
|
size_t klen = 5+hdr->name_len; |
1645
|
329
|
50
|
|
|
|
|
if (kbuflen < klen) { |
1646
|
0
|
|
|
|
|
|
kbuflen = klen; |
1647
|
0
|
|
|
|
|
|
kbuf = Renew(kbuf, kbuflen, char); |
1648
|
|
|
|
|
|
|
} |
1649
|
329
|
|
|
|
|
|
char *key = kbuf + 5; |
1650
|
3016
|
100
|
|
|
|
|
for (j=0; jname_len; j++) { |
1651
|
2687
|
|
|
|
|
|
char n = hdr->name[j]; |
1652
|
2687
|
100
|
|
|
|
|
*key++ = (n == '-') ? '_' : toupper(n); |
1653
|
|
|
|
|
|
|
} |
1654
|
|
|
|
|
|
|
|
1655
|
329
|
|
|
|
|
|
SV **val = hv_fetch(e, kbuf, klen, 1); |
1656
|
|
|
|
|
|
|
trace("adding header to env (fd %d) %.*s: %.*s\n", |
1657
|
|
|
|
|
|
|
c->fd, (int)klen, kbuf, (int)hdr->value_len, hdr->value); |
1658
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
assert(val != NULL); // "fetch is store" flag should ensure this |
1660
|
329
|
100
|
|
|
|
|
if (unlikely(SvPOK(*val))) { |
1661
|
|
|
|
|
|
|
trace("... is multivalue\n"); |
1662
|
|
|
|
|
|
|
// extend header with comma |
1663
|
1
|
|
|
|
|
|
sv_catpvn(*val, ", ", 2); |
1664
|
1
|
|
|
|
|
|
sv_catpvn(*val, hdr->value, hdr->value_len); |
1665
|
|
|
|
|
|
|
} |
1666
|
|
|
|
|
|
|
else { |
1667
|
|
|
|
|
|
|
// change from undef to a real value |
1668
|
328
|
|
|
|
|
|
sv_setpvn(*val, hdr->value, hdr->value_len); |
1669
|
|
|
|
|
|
|
} |
1670
|
|
|
|
|
|
|
} |
1671
|
99
|
|
|
|
|
|
Safefree(kbuf); |
1672
|
|
|
|
|
|
|
|
1673
|
99
|
|
|
|
|
|
return e; |
1674
|
|
|
|
|
|
|
} |
1675
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
static void |
1677
|
98
|
|
|
|
|
|
feersum_start_response (pTHX_ struct feer_conn *c, SV *message, AV *headers, |
1678
|
|
|
|
|
|
|
int streaming) |
1679
|
|
|
|
|
|
|
{ |
1680
|
|
|
|
|
|
|
const char *ptr; |
1681
|
|
|
|
|
|
|
I32 i; |
1682
|
|
|
|
|
|
|
|
1683
|
|
|
|
|
|
|
trace("start_response fd=%d streaming=%d\n", c->fd, streaming); |
1684
|
|
|
|
|
|
|
|
1685
|
98
|
50
|
|
|
|
|
if (unlikely(c->responding != RESPOND_NOT_STARTED)) |
1686
|
0
|
|
|
|
|
|
croak("already responding?!"); |
1687
|
98
|
100
|
|
|
|
|
change_responding_state(c, streaming ? RESPOND_STREAMING : RESPOND_NORMAL); |
1688
|
|
|
|
|
|
|
|
1689
|
98
|
50
|
|
|
|
|
if (unlikely(!SvOK(message) || !(SvIOK(message) || SvPOK(message)))) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1690
|
0
|
|
|
|
|
|
croak("Must define an HTTP status code or message"); |
1691
|
|
|
|
|
|
|
} |
1692
|
|
|
|
|
|
|
|
1693
|
98
|
|
|
|
|
|
I32 avl = av_len(headers); |
1694
|
98
|
50
|
|
|
|
|
if (unlikely(avl+1 % 2 == 1)) { |
1695
|
0
|
|
|
|
|
|
croak("expected even-length array, got %d", avl+1); |
1696
|
|
|
|
|
|
|
} |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
// int or 3 chars? use a stock message |
1699
|
98
|
|
|
|
|
|
UV code = 0; |
1700
|
98
|
100
|
|
|
|
|
if (SvIOK(message)) |
1701
|
77
|
50
|
|
|
|
|
code = SvIV(message); |
1702
|
21
|
50
|
|
|
|
|
else if (SvUOK(message)) |
1703
|
0
|
0
|
|
|
|
|
code = SvUV(message); |
1704
|
|
|
|
|
|
|
else { |
1705
|
21
|
|
|
|
|
|
const int numtype = grok_number(SvPVX_const(message),3,&code); |
1706
|
21
|
50
|
|
|
|
|
if (unlikely(numtype != IS_NUMBER_IN_UV)) |
1707
|
0
|
|
|
|
|
|
code = 0; |
1708
|
|
|
|
|
|
|
} |
1709
|
|
|
|
|
|
|
trace2("starting response fd=%d code=%"UVuf"\n",c->fd,code); |
1710
|
|
|
|
|
|
|
|
1711
|
98
|
50
|
|
|
|
|
if (unlikely(!code)) |
1712
|
0
|
|
|
|
|
|
croak("first parameter is not a number or doesn't start with digits"); |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
// for PSGI it's always just an IV so optimize for that |
1715
|
98
|
100
|
|
|
|
|
if (likely(!SvPOK(message) || SvCUR(message) == 3)) { |
|
|
100
|
|
|
|
|
|
1716
|
78
|
|
|
|
|
|
ptr = http_code_to_msg(code); |
1717
|
78
|
|
|
|
|
|
message = sv_2mortal(newSVpvf("%"UVuf" %s",code,ptr)); |
1718
|
|
|
|
|
|
|
} |
1719
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
// don't generate or strip Content-Length headers for 304 or 1xx |
1721
|
98
|
100
|
|
|
|
|
c->auto_cl = (code == 304 || (100 <= code && code <= 199)) ? 0 : 1; |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1722
|
|
|
|
|
|
|
|
1723
|
98
|
100
|
|
|
|
|
add_const_to_wbuf(c, c->is_http11 ? "HTTP/1.1 " : "HTTP/1.0 ", 9); |
1724
|
98
|
|
|
|
|
|
add_sv_to_wbuf(c, message); |
1725
|
98
|
|
|
|
|
|
add_crlf_to_wbuf(c); |
1726
|
|
|
|
|
|
|
|
1727
|
237
|
100
|
|
|
|
|
for (i=0; i
|
1728
|
139
|
|
|
|
|
|
SV **hdr = av_fetch(headers, i, 0); |
1729
|
139
|
50
|
|
|
|
|
if (unlikely(!hdr || !SvOK(*hdr))) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
trace("skipping undef header key"); |
1731
|
8
|
|
|
|
|
|
continue; |
1732
|
|
|
|
|
|
|
} |
1733
|
|
|
|
|
|
|
|
1734
|
139
|
|
|
|
|
|
SV **val = av_fetch(headers, i+1, 0); |
1735
|
139
|
50
|
|
|
|
|
if (unlikely(!val || !SvOK(*val))) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1736
|
|
|
|
|
|
|
trace("skipping undef header value"); |
1737
|
0
|
|
|
|
|
|
continue; |
1738
|
|
|
|
|
|
|
} |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
STRLEN hlen; |
1741
|
139
|
50
|
|
|
|
|
const char *hp = SvPV(*hdr, hlen); |
1742
|
277
|
|
|
|
|
|
if (likely(c->auto_cl) && |
1743
|
138
|
|
|
|
|
|
unlikely(str_case_eq("content-length",14,hp,hlen))) |
1744
|
|
|
|
|
|
|
{ |
1745
|
|
|
|
|
|
|
trace("ignoring content-length header in the response\n"); |
1746
|
8
|
|
|
|
|
|
continue; |
1747
|
|
|
|
|
|
|
} |
1748
|
|
|
|
|
|
|
|
1749
|
131
|
|
|
|
|
|
add_sv_to_wbuf(c, *hdr); |
1750
|
131
|
|
|
|
|
|
add_const_to_wbuf(c, ": ", 2); |
1751
|
131
|
|
|
|
|
|
add_sv_to_wbuf(c, *val); |
1752
|
131
|
|
|
|
|
|
add_crlf_to_wbuf(c); |
1753
|
|
|
|
|
|
|
} |
1754
|
|
|
|
|
|
|
|
1755
|
98
|
100
|
|
|
|
|
if (streaming) { |
1756
|
28
|
100
|
|
|
|
|
if (c->is_http11) |
1757
|
24
|
|
|
|
|
|
add_const_to_wbuf(c, "Transfer-Encoding: chunked" CRLFx2, 30); |
1758
|
|
|
|
|
|
|
else |
1759
|
4
|
|
|
|
|
|
add_const_to_wbuf(c, "Connection: close" CRLFx2, 21); |
1760
|
|
|
|
|
|
|
} |
1761
|
|
|
|
|
|
|
|
1762
|
98
|
|
|
|
|
|
conn_write_ready(c); |
1763
|
98
|
|
|
|
|
|
} |
1764
|
|
|
|
|
|
|
|
1765
|
|
|
|
|
|
|
static size_t |
1766
|
70
|
|
|
|
|
|
feersum_write_whole_body (pTHX_ struct feer_conn *c, SV *body) |
1767
|
|
|
|
|
|
|
{ |
1768
|
|
|
|
|
|
|
size_t RETVAL; |
1769
|
|
|
|
|
|
|
int i; |
1770
|
70
|
|
|
|
|
|
bool body_is_string = 0; |
1771
|
|
|
|
|
|
|
STRLEN cur; |
1772
|
|
|
|
|
|
|
|
1773
|
70
|
50
|
|
|
|
|
if (c->responding != RESPOND_NORMAL) |
1774
|
0
|
|
|
|
|
|
croak("can't use write_whole_body when in streaming mode"); |
1775
|
|
|
|
|
|
|
|
1776
|
70
|
50
|
|
|
|
|
if (!SvOK(body)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1777
|
0
|
|
|
|
|
|
body = sv_2mortal(newSVpvs("")); |
1778
|
0
|
|
|
|
|
|
body_is_string = 1; |
1779
|
|
|
|
|
|
|
} |
1780
|
70
|
100
|
|
|
|
|
else if (SvROK(body)) { |
1781
|
67
|
|
|
|
|
|
SV *refd = SvRV(body); |
1782
|
67
|
100
|
|
|
|
|
if (SvOK(refd) && !SvROK(refd)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1783
|
2
|
|
|
|
|
|
body = refd; |
1784
|
2
|
|
|
|
|
|
body_is_string = 1; |
1785
|
|
|
|
|
|
|
} |
1786
|
65
|
50
|
|
|
|
|
else if (SvTYPE(refd) != SVt_PVAV) { |
1787
|
67
|
|
|
|
|
|
croak("body must be a scalar, scalar reference or array reference"); |
1788
|
|
|
|
|
|
|
} |
1789
|
|
|
|
|
|
|
} |
1790
|
|
|
|
|
|
|
else { |
1791
|
3
|
|
|
|
|
|
body_is_string = 1; |
1792
|
|
|
|
|
|
|
} |
1793
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
SV *cl_sv; // content-length future |
1795
|
|
|
|
|
|
|
struct iovec *cl_iov; |
1796
|
70
|
100
|
|
|
|
|
if (likely(c->auto_cl)) |
1797
|
67
|
|
|
|
|
|
add_placeholder_to_wbuf(c, &cl_sv, &cl_iov); |
1798
|
|
|
|
|
|
|
else |
1799
|
3
|
|
|
|
|
|
add_crlf_to_wbuf(c); |
1800
|
|
|
|
|
|
|
|
1801
|
70
|
100
|
|
|
|
|
if (body_is_string) { |
1802
|
5
|
|
|
|
|
|
cur = add_sv_to_wbuf(c,body); |
1803
|
5
|
|
|
|
|
|
RETVAL = cur; |
1804
|
|
|
|
|
|
|
} |
1805
|
|
|
|
|
|
|
else { |
1806
|
65
|
|
|
|
|
|
AV *abody = (AV*)SvRV(body); |
1807
|
65
|
|
|
|
|
|
I32 amax = av_len(abody); |
1808
|
65
|
|
|
|
|
|
RETVAL = 0; |
1809
|
156
|
100
|
|
|
|
|
for (i=0; i<=amax; i++) { |
1810
|
91
|
|
|
|
|
|
SV *sv = fetch_av_normal(aTHX_ abody, i); |
1811
|
91
|
100
|
|
|
|
|
if (unlikely(!sv)) continue; |
1812
|
90
|
|
|
|
|
|
cur = add_sv_to_wbuf(c,sv); |
1813
|
|
|
|
|
|
|
trace("body part i=%d sv=%p cur=%"Sz_uf"\n", i, sv, (Sz)cur); |
1814
|
90
|
|
|
|
|
|
RETVAL += cur; |
1815
|
|
|
|
|
|
|
} |
1816
|
|
|
|
|
|
|
} |
1817
|
|
|
|
|
|
|
|
1818
|
70
|
100
|
|
|
|
|
if (likely(c->auto_cl)) { |
1819
|
67
|
|
|
|
|
|
sv_setpvf(cl_sv, "Content-Length: %"Sz_uf"" CRLFx2, (Sz)RETVAL); |
1820
|
67
|
|
|
|
|
|
update_wbuf_placeholder(c, cl_sv, cl_iov); |
1821
|
|
|
|
|
|
|
} |
1822
|
|
|
|
|
|
|
|
1823
|
70
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
1824
|
70
|
|
|
|
|
|
conn_write_ready(c); |
1825
|
70
|
|
|
|
|
|
return RETVAL; |
1826
|
|
|
|
|
|
|
} |
1827
|
|
|
|
|
|
|
|
1828
|
|
|
|
|
|
|
static void |
1829
|
17
|
|
|
|
|
|
feersum_start_psgi_streaming(pTHX_ struct feer_conn *c, SV *streamer) |
1830
|
|
|
|
|
|
|
{ |
1831
|
17
|
|
|
|
|
|
dSP; |
1832
|
17
|
|
|
|
|
|
ENTER; |
1833
|
17
|
|
|
|
|
|
SAVETMPS; |
1834
|
17
|
50
|
|
|
|
|
PUSHMARK(SP); |
1835
|
17
|
50
|
|
|
|
|
mXPUSHs(feer_conn_2sv(c)); |
1836
|
17
|
50
|
|
|
|
|
XPUSHs(streamer); |
1837
|
17
|
|
|
|
|
|
PUTBACK; |
1838
|
17
|
|
|
|
|
|
call_method("_initiate_streaming_psgi", G_DISCARD|G_EVAL|G_VOID); |
1839
|
17
|
|
|
|
|
|
SPAGAIN; |
1840
|
17
|
50
|
|
|
|
|
if (unlikely(SvTRUE(ERRSV))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1841
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "PSGI stream initiator"); |
1842
|
|
|
|
|
|
|
} |
1843
|
17
|
|
|
|
|
|
PUTBACK; |
1844
|
17
|
50
|
|
|
|
|
FREETMPS; |
1845
|
17
|
|
|
|
|
|
LEAVE; |
1846
|
17
|
|
|
|
|
|
} |
1847
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
static void |
1849
|
78
|
|
|
|
|
|
feersum_handle_psgi_response( |
1850
|
|
|
|
|
|
|
pTHX_ struct feer_conn *c, SV *ret, bool can_recurse) |
1851
|
|
|
|
|
|
|
{ |
1852
|
78
|
50
|
|
|
|
|
if (unlikely(!SvOK(ret) || !SvROK(ret))) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1853
|
0
|
0
|
|
|
|
|
sv_setpvs(ERRSV, "Invalid PSGI response (expected reference)"); |
1854
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "PSGI request"); |
1855
|
0
|
|
|
|
|
|
return; |
1856
|
|
|
|
|
|
|
} |
1857
|
|
|
|
|
|
|
|
1858
|
78
|
50
|
|
|
|
|
if (SvOK(ret) && unlikely(!IsArrayRef(ret))) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1859
|
17
|
50
|
|
|
|
|
if (likely(can_recurse)) { |
1860
|
|
|
|
|
|
|
trace("PSGI response non-array, c=%p ret=%p\n", c, ret); |
1861
|
17
|
|
|
|
|
|
feersum_start_psgi_streaming(aTHX_ c, ret); |
1862
|
|
|
|
|
|
|
} |
1863
|
|
|
|
|
|
|
else { |
1864
|
0
|
0
|
|
|
|
|
sv_setpvs(ERRSV, "PSGI attempt to recurse in a streaming callback"); |
1865
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "PSGI request"); |
1866
|
|
|
|
|
|
|
} |
1867
|
17
|
|
|
|
|
|
return; |
1868
|
|
|
|
|
|
|
} |
1869
|
|
|
|
|
|
|
|
1870
|
61
|
|
|
|
|
|
AV *psgi_triplet = (AV*)SvRV(ret); |
1871
|
61
|
50
|
|
|
|
|
if (unlikely(av_len(psgi_triplet)+1 != 3)) { |
1872
|
0
|
0
|
|
|
|
|
sv_setpvs(ERRSV, "Invalid PSGI array response (expected triplet)"); |
1873
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "PSGI request"); |
1874
|
0
|
|
|
|
|
|
return; |
1875
|
|
|
|
|
|
|
} |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
trace("PSGI response triplet, c=%p av=%p\n", c, psgi_triplet); |
1878
|
|
|
|
|
|
|
// we know there's three elems so *should* be safe to de-ref |
1879
|
61
|
|
|
|
|
|
SV *msg = *(av_fetch(psgi_triplet,0,0)); |
1880
|
61
|
|
|
|
|
|
SV *hdrs = *(av_fetch(psgi_triplet,1,0)); |
1881
|
61
|
|
|
|
|
|
SV *body = *(av_fetch(psgi_triplet,2,0)); |
1882
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
AV *headers; |
1884
|
61
|
50
|
|
|
|
|
if (IsArrayRef(hdrs)) |
|
|
50
|
|
|
|
|
|
1885
|
61
|
|
|
|
|
|
headers = (AV*)SvRV(hdrs); |
1886
|
|
|
|
|
|
|
else { |
1887
|
0
|
0
|
|
|
|
|
sv_setpvs(ERRSV, "PSGI Headers must be an array-ref"); |
1888
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "PSGI request"); |
1889
|
0
|
|
|
|
|
|
return; |
1890
|
|
|
|
|
|
|
} |
1891
|
|
|
|
|
|
|
|
1892
|
61
|
50
|
|
|
|
|
if (likely(IsArrayRef(body))) { |
|
|
100
|
|
|
|
|
|
1893
|
48
|
|
|
|
|
|
feersum_start_response(aTHX_ c, msg, headers, 0); |
1894
|
48
|
|
|
|
|
|
feersum_write_whole_body(aTHX_ c, body); |
1895
|
|
|
|
|
|
|
} |
1896
|
13
|
50
|
|
|
|
|
else if (likely(SvROK(body))) { // probaby an IO::Handle-like object |
1897
|
13
|
|
|
|
|
|
feersum_start_response(aTHX_ c, msg, headers, 1); |
1898
|
13
|
|
|
|
|
|
c->poll_write_cb = newSVsv(body); |
1899
|
13
|
|
|
|
|
|
c->poll_write_cb_is_io_handle = 1; |
1900
|
13
|
|
|
|
|
|
conn_write_ready(c); |
1901
|
|
|
|
|
|
|
} |
1902
|
|
|
|
|
|
|
else { |
1903
|
0
|
0
|
|
|
|
|
sv_setpvs(ERRSV, "Expected PSGI array-ref or IO::Handle-like body"); |
1904
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "PSGI request"); |
1905
|
0
|
|
|
|
|
|
return; |
1906
|
|
|
|
|
|
|
} |
1907
|
|
|
|
|
|
|
} |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
static int |
1910
|
23
|
|
|
|
|
|
feersum_close_handle (pTHX_ struct feer_conn *c, bool is_writer) |
1911
|
|
|
|
|
|
|
{ |
1912
|
|
|
|
|
|
|
int RETVAL; |
1913
|
23
|
100
|
|
|
|
|
if (is_writer) { |
1914
|
|
|
|
|
|
|
trace("close writer fd=%d, c=%p, refcnt=%d\n", c->fd, c, SvREFCNT(c->self)); |
1915
|
19
|
50
|
|
|
|
|
if (c->poll_write_cb) { |
1916
|
0
|
|
|
|
|
|
SvREFCNT_dec(c->poll_write_cb); |
1917
|
0
|
|
|
|
|
|
c->poll_write_cb = NULL; |
1918
|
|
|
|
|
|
|
} |
1919
|
19
|
100
|
|
|
|
|
if (c->responding < RESPOND_SHUTDOWN) { |
1920
|
15
|
|
|
|
|
|
finish_wbuf(c); |
1921
|
15
|
|
|
|
|
|
conn_write_ready(c); |
1922
|
15
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
1923
|
|
|
|
|
|
|
} |
1924
|
19
|
|
|
|
|
|
RETVAL = 1; |
1925
|
|
|
|
|
|
|
} |
1926
|
|
|
|
|
|
|
else { |
1927
|
|
|
|
|
|
|
trace("close reader fd=%d, c=%p\n", c->fd, c); |
1928
|
|
|
|
|
|
|
// TODO: ref-dec poll_read_cb |
1929
|
4
|
100
|
|
|
|
|
if (c->rbuf) { |
1930
|
1
|
|
|
|
|
|
SvREFCNT_dec(c->rbuf); |
1931
|
1
|
|
|
|
|
|
c->rbuf = NULL; |
1932
|
|
|
|
|
|
|
} |
1933
|
4
|
|
|
|
|
|
RETVAL = shutdown(c->fd, SHUT_RD); |
1934
|
4
|
|
|
|
|
|
change_receiving_state(c, RECEIVE_SHUTDOWN); |
1935
|
|
|
|
|
|
|
} |
1936
|
|
|
|
|
|
|
|
1937
|
|
|
|
|
|
|
// disassociate the handle from the conn |
1938
|
23
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
1939
|
23
|
|
|
|
|
|
return RETVAL; |
1940
|
|
|
|
|
|
|
} |
1941
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
static SV* |
1943
|
6
|
|
|
|
|
|
feersum_conn_guard(pTHX_ struct feer_conn *c, SV *guard) |
1944
|
|
|
|
|
|
|
{ |
1945
|
6
|
100
|
|
|
|
|
if (guard) { |
1946
|
4
|
100
|
|
|
|
|
if (c->ext_guard) SvREFCNT_dec(c->ext_guard); |
1947
|
4
|
50
|
|
|
|
|
c->ext_guard = SvOK(guard) ? newSVsv(guard) : NULL; |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
} |
1949
|
6
|
50
|
|
|
|
|
return c->ext_guard ? newSVsv(c->ext_guard) : &PL_sv_undef; |
1950
|
|
|
|
|
|
|
} |
1951
|
|
|
|
|
|
|
|
1952
|
|
|
|
|
|
|
static void |
1953
|
2
|
|
|
|
|
|
call_died (pTHX_ struct feer_conn *c, const char *cb_type) |
1954
|
|
|
|
|
|
|
{ |
1955
|
2
|
|
|
|
|
|
dSP; |
1956
|
|
|
|
|
|
|
#if DEBUG >= 1 |
1957
|
|
|
|
|
|
|
trace("An error was thrown in the %s callback: %-p\n",cb_type,ERRSV); |
1958
|
|
|
|
|
|
|
#endif |
1959
|
2
|
50
|
|
|
|
|
PUSHMARK(SP); |
1960
|
2
|
50
|
|
|
|
|
mXPUSHs(newSVsv(ERRSV)); |
|
|
50
|
|
|
|
|
|
1961
|
2
|
|
|
|
|
|
PUTBACK; |
1962
|
2
|
|
|
|
|
|
call_pv("Feersum::DIED", G_DISCARD|G_EVAL|G_VOID|G_KEEPERR); |
1963
|
2
|
|
|
|
|
|
SPAGAIN; |
1964
|
|
|
|
|
|
|
|
1965
|
2
|
|
|
|
|
|
respond_with_server_error(c,"Request handler exception.\n",0,500); |
1966
|
2
|
50
|
|
|
|
|
sv_setsv(ERRSV, &PL_sv_undef); |
1967
|
2
|
|
|
|
|
|
} |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
static void |
1970
|
108
|
|
|
|
|
|
call_request_callback (struct feer_conn *c) |
1971
|
|
|
|
|
|
|
{ |
1972
|
|
|
|
|
|
|
dTHX; |
1973
|
108
|
|
|
|
|
|
dSP; |
1974
|
|
|
|
|
|
|
int flags; |
1975
|
108
|
|
|
|
|
|
c->in_callback++; |
1976
|
108
|
|
|
|
|
|
SvREFCNT_inc_void_NN(c->self); |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
trace("request callback c=%p\n", c); |
1979
|
|
|
|
|
|
|
|
1980
|
108
|
|
|
|
|
|
ENTER; |
1981
|
108
|
|
|
|
|
|
SAVETMPS; |
1982
|
108
|
50
|
|
|
|
|
PUSHMARK(SP); |
1983
|
|
|
|
|
|
|
|
1984
|
108
|
100
|
|
|
|
|
if (request_cb_is_psgi) { |
1985
|
73
|
|
|
|
|
|
HV *env = feersum_env(aTHX_ c); |
1986
|
73
|
50
|
|
|
|
|
mXPUSHs(newRV_noinc((SV*)env)); |
1987
|
73
|
|
|
|
|
|
flags = G_EVAL|G_SCALAR; |
1988
|
|
|
|
|
|
|
} |
1989
|
|
|
|
|
|
|
else { |
1990
|
35
|
50
|
|
|
|
|
mXPUSHs(feer_conn_2sv(c)); |
1991
|
35
|
|
|
|
|
|
flags = G_DISCARD|G_EVAL|G_VOID; |
1992
|
|
|
|
|
|
|
} |
1993
|
|
|
|
|
|
|
|
1994
|
108
|
|
|
|
|
|
PUTBACK; |
1995
|
108
|
|
|
|
|
|
int returned = call_sv(request_cb_cv, flags); |
1996
|
108
|
|
|
|
|
|
SPAGAIN; |
1997
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
trace("called request callback, errsv? %d\n", SvTRUE(ERRSV) ? 1 : 0); |
1999
|
|
|
|
|
|
|
|
2000
|
108
|
50
|
|
|
|
|
if (unlikely(SvTRUE(ERRSV))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2001
|
2
|
|
|
|
|
|
call_died(aTHX_ c, "request"); |
2002
|
2
|
|
|
|
|
|
returned = 0; // pretend nothing got returned |
2003
|
|
|
|
|
|
|
} |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
SV *psgi_response; |
2006
|
108
|
100
|
|
|
|
|
if (request_cb_is_psgi && likely(returned >= 1)) { |
|
|
100
|
|
|
|
|
|
2007
|
72
|
|
|
|
|
|
psgi_response = POPs; |
2008
|
72
|
|
|
|
|
|
SvREFCNT_inc_void_NN(psgi_response); |
2009
|
|
|
|
|
|
|
} |
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
trace("leaving request callback\n"); |
2012
|
108
|
|
|
|
|
|
PUTBACK; |
2013
|
|
|
|
|
|
|
|
2014
|
108
|
100
|
|
|
|
|
if (request_cb_is_psgi && likely(returned >= 1)) { |
|
|
100
|
|
|
|
|
|
2015
|
72
|
|
|
|
|
|
feersum_handle_psgi_response(aTHX_ c, psgi_response, 1); // can_recurse |
2016
|
72
|
|
|
|
|
|
SvREFCNT_dec(psgi_response); |
2017
|
|
|
|
|
|
|
} |
2018
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
//fangyousong |
2020
|
108
|
100
|
|
|
|
|
if (request_cb_is_psgi && c->expected_cl > 0) { |
|
|
100
|
|
|
|
|
|
2021
|
3
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
2022
|
|
|
|
|
|
|
} |
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
|
2025
|
108
|
|
|
|
|
|
c->in_callback--; |
2026
|
108
|
|
|
|
|
|
SvREFCNT_dec(c->self); |
2027
|
|
|
|
|
|
|
|
2028
|
108
|
50
|
|
|
|
|
FREETMPS; |
2029
|
108
|
|
|
|
|
|
LEAVE; |
2030
|
108
|
|
|
|
|
|
} |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
static void |
2033
|
4
|
|
|
|
|
|
call_poll_callback (struct feer_conn *c, bool is_write) |
2034
|
|
|
|
|
|
|
{ |
2035
|
|
|
|
|
|
|
dTHX; |
2036
|
4
|
|
|
|
|
|
dSP; |
2037
|
|
|
|
|
|
|
|
2038
|
4
|
50
|
|
|
|
|
SV *cb = (is_write) ? c->poll_write_cb : NULL; |
2039
|
|
|
|
|
|
|
|
2040
|
4
|
50
|
|
|
|
|
if (unlikely(cb == NULL)) return; |
2041
|
|
|
|
|
|
|
|
2042
|
4
|
|
|
|
|
|
c->in_callback++; |
2043
|
|
|
|
|
|
|
|
2044
|
|
|
|
|
|
|
trace("%s poll callback c=%p cbrv=%p\n", |
2045
|
|
|
|
|
|
|
is_write ? "write" : "read", c, cb); |
2046
|
|
|
|
|
|
|
|
2047
|
4
|
|
|
|
|
|
ENTER; |
2048
|
4
|
|
|
|
|
|
SAVETMPS; |
2049
|
4
|
50
|
|
|
|
|
PUSHMARK(SP); |
2050
|
4
|
50
|
|
|
|
|
mXPUSHs(new_feer_conn_handle(aTHX_ c, is_write)); |
2051
|
4
|
|
|
|
|
|
PUTBACK; |
2052
|
4
|
|
|
|
|
|
call_sv(cb, G_DISCARD|G_EVAL|G_VOID); |
2053
|
4
|
|
|
|
|
|
SPAGAIN; |
2054
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
trace("called %s poll callback, errsv? %d\n", |
2056
|
|
|
|
|
|
|
is_write ? "write" : "read", SvTRUE(ERRSV) ? 1 : 0); |
2057
|
|
|
|
|
|
|
|
2058
|
4
|
50
|
|
|
|
|
if (unlikely(SvTRUE(ERRSV))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2059
|
0
|
0
|
|
|
|
|
call_died(aTHX_ c, is_write ? "write poll" : "read poll"); |
2060
|
|
|
|
|
|
|
} |
2061
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
trace("leaving %s poll callback\n", is_write ? "write" : "read"); |
2063
|
4
|
|
|
|
|
|
PUTBACK; |
2064
|
4
|
50
|
|
|
|
|
FREETMPS; |
2065
|
4
|
|
|
|
|
|
LEAVE; |
2066
|
|
|
|
|
|
|
|
2067
|
4
|
|
|
|
|
|
c->in_callback--; |
2068
|
|
|
|
|
|
|
} |
2069
|
|
|
|
|
|
|
|
2070
|
|
|
|
|
|
|
static void |
2071
|
38
|
|
|
|
|
|
pump_io_handle (struct feer_conn *c, SV *io) |
2072
|
|
|
|
|
|
|
{ |
2073
|
|
|
|
|
|
|
dTHX; |
2074
|
38
|
|
|
|
|
|
dSP; |
2075
|
|
|
|
|
|
|
|
2076
|
38
|
50
|
|
|
|
|
if (unlikely(io == NULL)) return; |
2077
|
|
|
|
|
|
|
|
2078
|
38
|
|
|
|
|
|
c->in_callback++; |
2079
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
trace("pump io handle %d\n", c->fd); |
2081
|
|
|
|
|
|
|
|
2082
|
38
|
|
|
|
|
|
ENTER; |
2083
|
38
|
|
|
|
|
|
SAVETMPS; |
2084
|
|
|
|
|
|
|
|
2085
|
|
|
|
|
|
|
// Emulate `local $/ = \4096;` |
2086
|
38
|
|
|
|
|
|
SV *old_rs = PL_rs; |
2087
|
38
|
|
|
|
|
|
PL_rs = sv_2mortal(newRV_noinc(newSViv(4096))); |
2088
|
38
|
|
|
|
|
|
sv_setsv(get_sv("/", GV_ADD), PL_rs); |
2089
|
|
|
|
|
|
|
|
2090
|
38
|
50
|
|
|
|
|
PUSHMARK(SP); |
2091
|
38
|
50
|
|
|
|
|
XPUSHs(c->poll_write_cb); |
2092
|
38
|
|
|
|
|
|
PUTBACK; |
2093
|
38
|
|
|
|
|
|
int returned = call_method("getline", G_SCALAR|G_EVAL); |
2094
|
38
|
|
|
|
|
|
SPAGAIN; |
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
trace("called getline on io handle fd=%d errsv=%d returned=%d\n", |
2097
|
|
|
|
|
|
|
c->fd, SvTRUE(ERRSV) ? 1 : 0, returned); |
2098
|
|
|
|
|
|
|
|
2099
|
38
|
50
|
|
|
|
|
if (unlikely(SvTRUE(ERRSV))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2100
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "getline on io handle"); |
2101
|
0
|
|
|
|
|
|
goto done_pump_io; |
2102
|
|
|
|
|
|
|
} |
2103
|
|
|
|
|
|
|
|
2104
|
38
|
|
|
|
|
|
SV *ret = NULL; |
2105
|
38
|
50
|
|
|
|
|
if (returned > 0) |
2106
|
38
|
|
|
|
|
|
ret = POPs; |
2107
|
38
|
50
|
|
|
|
|
if (ret && SvMAGICAL(ret)) |
|
|
50
|
|
|
|
|
|
2108
|
0
|
|
|
|
|
|
ret = sv_2mortal(newSVsv(ret)); |
2109
|
|
|
|
|
|
|
|
2110
|
38
|
50
|
|
|
|
|
if (unlikely(!ret || !SvOK(ret))) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2111
|
|
|
|
|
|
|
// returned undef, so call the close method out of niceity |
2112
|
13
|
50
|
|
|
|
|
PUSHMARK(SP); |
2113
|
13
|
50
|
|
|
|
|
XPUSHs(c->poll_write_cb); |
2114
|
13
|
|
|
|
|
|
PUTBACK; |
2115
|
13
|
|
|
|
|
|
call_method("close", G_VOID|G_DISCARD|G_EVAL); |
2116
|
13
|
|
|
|
|
|
SPAGAIN; |
2117
|
|
|
|
|
|
|
|
2118
|
13
|
50
|
|
|
|
|
if (unlikely(SvTRUE(ERRSV))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2119
|
0
|
0
|
|
|
|
|
trouble("Couldn't close body IO handle: %-p",ERRSV); |
2120
|
|
|
|
|
|
|
} |
2121
|
|
|
|
|
|
|
|
2122
|
13
|
|
|
|
|
|
SvREFCNT_dec(c->poll_write_cb); |
2123
|
13
|
|
|
|
|
|
c->poll_write_cb = NULL; |
2124
|
13
|
|
|
|
|
|
finish_wbuf(c); |
2125
|
13
|
|
|
|
|
|
change_responding_state(c, RESPOND_SHUTDOWN); |
2126
|
|
|
|
|
|
|
|
2127
|
13
|
|
|
|
|
|
goto done_pump_io; |
2128
|
|
|
|
|
|
|
} |
2129
|
|
|
|
|
|
|
|
2130
|
25
|
50
|
|
|
|
|
if (c->is_http11) |
2131
|
25
|
|
|
|
|
|
add_chunk_sv_to_wbuf(c, ret); |
2132
|
|
|
|
|
|
|
else |
2133
|
0
|
|
|
|
|
|
add_sv_to_wbuf(c, ret); |
2134
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
done_pump_io: |
2136
|
|
|
|
|
|
|
trace("leaving pump io handle %d\n", c->fd); |
2137
|
|
|
|
|
|
|
|
2138
|
38
|
|
|
|
|
|
PUTBACK; |
2139
|
38
|
50
|
|
|
|
|
FREETMPS; |
2140
|
38
|
|
|
|
|
|
LEAVE; |
2141
|
|
|
|
|
|
|
|
2142
|
38
|
|
|
|
|
|
PL_rs = old_rs; |
2143
|
38
|
|
|
|
|
|
sv_setsv(get_sv("/", GV_ADD), old_rs); |
2144
|
|
|
|
|
|
|
|
2145
|
38
|
|
|
|
|
|
c->in_callback--; |
2146
|
|
|
|
|
|
|
} |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
static int |
2149
|
8
|
|
|
|
|
|
psgix_io_svt_get (pTHX_ SV *sv, MAGIC *mg) |
2150
|
|
|
|
|
|
|
{ |
2151
|
8
|
|
|
|
|
|
dSP; |
2152
|
|
|
|
|
|
|
|
2153
|
8
|
|
|
|
|
|
struct feer_conn *c = sv_2feer_conn(mg->mg_obj); |
2154
|
|
|
|
|
|
|
trace("invoking psgix.io magic for fd=%d\n", c->fd); |
2155
|
|
|
|
|
|
|
|
2156
|
8
|
|
|
|
|
|
sv_unmagic(sv, PERL_MAGIC_ext); |
2157
|
|
|
|
|
|
|
|
2158
|
8
|
|
|
|
|
|
ENTER; |
2159
|
8
|
|
|
|
|
|
SAVETMPS; |
2160
|
|
|
|
|
|
|
|
2161
|
8
|
50
|
|
|
|
|
PUSHMARK(SP); |
2162
|
8
|
50
|
|
|
|
|
XPUSHs(sv); |
2163
|
8
|
50
|
|
|
|
|
mXPUSHs(newSViv(c->fd)); |
2164
|
8
|
|
|
|
|
|
PUTBACK; |
2165
|
|
|
|
|
|
|
|
2166
|
8
|
|
|
|
|
|
call_pv("Feersum::Connection::_raw", G_VOID|G_DISCARD|G_EVAL); |
2167
|
8
|
|
|
|
|
|
SPAGAIN; |
2168
|
|
|
|
|
|
|
|
2169
|
8
|
50
|
|
|
|
|
if (unlikely(SvTRUE(ERRSV))) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2170
|
0
|
|
|
|
|
|
call_died(aTHX_ c, "psgix.io magic"); |
2171
|
|
|
|
|
|
|
} |
2172
|
|
|
|
|
|
|
else { |
2173
|
8
|
|
|
|
|
|
SV *io_glob = SvRV(sv); |
2174
|
8
|
|
|
|
|
|
GvSV(io_glob) = newRV_inc(c->self); |
2175
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
// Put whatever remainder data into the socket buffer. |
2177
|
|
|
|
|
|
|
// Optimizes for the websocket case. |
2178
|
|
|
|
|
|
|
// |
2179
|
|
|
|
|
|
|
// TODO: For keepalive support the opposite operation is required; |
2180
|
|
|
|
|
|
|
// pull the data out of the socket buffer and back into feersum. |
2181
|
8
|
50
|
|
|
|
|
if (likely(c->rbuf && SvOK(c->rbuf) && SvCUR(c->rbuf))) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2182
|
|
|
|
|
|
|
STRLEN rbuf_len; |
2183
|
8
|
50
|
|
|
|
|
const char *rbuf_ptr = SvPV(c->rbuf, rbuf_len); |
2184
|
8
|
|
|
|
|
|
IO *io = GvIOp(io_glob); |
2185
|
|
|
|
|
|
|
assert(io != NULL); |
2186
|
8
|
|
|
|
|
|
PerlIO_unread(IoIFP(io), (const void *)rbuf_ptr, rbuf_len); |
2187
|
8
|
|
|
|
|
|
sv_setpvs(c->rbuf, ""); |
2188
|
|
|
|
|
|
|
} |
2189
|
|
|
|
|
|
|
|
2190
|
8
|
|
|
|
|
|
stop_read_watcher(c); |
2191
|
8
|
|
|
|
|
|
stop_read_timer(c); |
2192
|
|
|
|
|
|
|
// don't stop write watcher in case there's outstanding data. |
2193
|
|
|
|
|
|
|
} |
2194
|
|
|
|
|
|
|
|
2195
|
8
|
|
|
|
|
|
PUTBACK; |
2196
|
8
|
50
|
|
|
|
|
FREETMPS; |
2197
|
8
|
|
|
|
|
|
LEAVE; |
2198
|
8
|
|
|
|
|
|
return 0; |
2199
|
|
|
|
|
|
|
} |
2200
|
|
|
|
|
|
|
|
2201
|
|
|
|
|
|
|
MODULE = Feersum PACKAGE = Feersum |
2202
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
2204
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
void |
2206
|
|
|
|
|
|
|
set_server_name_and_port(SV *self, SV *name, SV *port) |
2207
|
|
|
|
|
|
|
PPCODE: |
2208
|
|
|
|
|
|
|
{ |
2209
|
29
|
50
|
|
|
|
|
if (feer_server_name) |
2210
|
0
|
|
|
|
|
|
SvREFCNT_dec(feer_server_name); |
2211
|
29
|
|
|
|
|
|
feer_server_name = newSVsv(name); |
2212
|
29
|
|
|
|
|
|
SvREADONLY_on(feer_server_name); |
2213
|
|
|
|
|
|
|
|
2214
|
29
|
50
|
|
|
|
|
if (feer_server_port) |
2215
|
0
|
|
|
|
|
|
SvREFCNT_dec(feer_server_port); |
2216
|
29
|
|
|
|
|
|
feer_server_port = newSVsv(port); |
2217
|
29
|
|
|
|
|
|
SvREADONLY_on(feer_server_port); |
2218
|
|
|
|
|
|
|
} |
2219
|
|
|
|
|
|
|
|
2220
|
|
|
|
|
|
|
void |
2221
|
|
|
|
|
|
|
accept_on_fd(SV *self, int fd) |
2222
|
|
|
|
|
|
|
PPCODE: |
2223
|
|
|
|
|
|
|
{ |
2224
|
|
|
|
|
|
|
trace("going to accept on %d\n",fd); |
2225
|
29
|
|
|
|
|
|
feersum_ev_loop = EV_DEFAULT; |
2226
|
|
|
|
|
|
|
|
2227
|
29
|
|
|
|
|
|
signal(SIGPIPE, SIG_IGN); |
2228
|
|
|
|
|
|
|
|
2229
|
29
|
|
|
|
|
|
ev_prepare_init(&ep, prepare_cb); |
2230
|
29
|
|
|
|
|
|
ev_prepare_start(feersum_ev_loop, &ep); |
2231
|
|
|
|
|
|
|
|
2232
|
29
|
|
|
|
|
|
ev_check_init(&ec, check_cb); |
2233
|
29
|
|
|
|
|
|
ev_check_start(feersum_ev_loop, &ec); |
2234
|
|
|
|
|
|
|
|
2235
|
29
|
|
|
|
|
|
ev_idle_init(&ei, idle_cb); |
2236
|
|
|
|
|
|
|
|
2237
|
29
|
|
|
|
|
|
ev_io_init(&accept_w, accept_cb, fd, EV_READ); |
2238
|
|
|
|
|
|
|
} |
2239
|
|
|
|
|
|
|
|
2240
|
|
|
|
|
|
|
void |
2241
|
|
|
|
|
|
|
unlisten (SV *self) |
2242
|
|
|
|
|
|
|
PPCODE: |
2243
|
|
|
|
|
|
|
{ |
2244
|
|
|
|
|
|
|
trace("stopping accept\n"); |
2245
|
2
|
|
|
|
|
|
ev_prepare_stop(feersum_ev_loop, &ep); |
2246
|
2
|
|
|
|
|
|
ev_check_stop(feersum_ev_loop, &ec); |
2247
|
2
|
|
|
|
|
|
ev_idle_stop(feersum_ev_loop, &ei); |
2248
|
2
|
|
|
|
|
|
ev_io_stop(feersum_ev_loop, &accept_w); |
2249
|
|
|
|
|
|
|
} |
2250
|
|
|
|
|
|
|
|
2251
|
|
|
|
|
|
|
void |
2252
|
|
|
|
|
|
|
request_handler(SV *self, SV *cb) |
2253
|
|
|
|
|
|
|
PROTOTYPE: $& |
2254
|
|
|
|
|
|
|
ALIAS: |
2255
|
|
|
|
|
|
|
psgi_request_handler = 1 |
2256
|
|
|
|
|
|
|
PPCODE: |
2257
|
|
|
|
|
|
|
{ |
2258
|
37
|
50
|
|
|
|
|
if (unlikely(!SvOK(cb) || !SvROK(cb))) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2259
|
0
|
|
|
|
|
|
croak("can't supply an undef handler"); |
2260
|
37
|
100
|
|
|
|
|
if (request_cb_cv) |
2261
|
8
|
|
|
|
|
|
SvREFCNT_dec(request_cb_cv); |
2262
|
37
|
|
|
|
|
|
request_cb_cv = newSVsv(cb); // copy so 5.8.7 overload magic sticks. |
2263
|
37
|
|
|
|
|
|
request_cb_is_psgi = ix; |
2264
|
|
|
|
|
|
|
trace("assigned %s request handler %p\n", |
2265
|
|
|
|
|
|
|
request_cb_is_psgi?"PSGI":"Feersum", request_cb_cv); |
2266
|
|
|
|
|
|
|
} |
2267
|
|
|
|
|
|
|
|
2268
|
|
|
|
|
|
|
void |
2269
|
|
|
|
|
|
|
graceful_shutdown (SV *self, SV *cb) |
2270
|
|
|
|
|
|
|
PROTOTYPE: $& |
2271
|
|
|
|
|
|
|
PPCODE: |
2272
|
|
|
|
|
|
|
{ |
2273
|
10
|
50
|
|
|
|
|
if (!IsCodeRef(cb)) |
|
|
50
|
|
|
|
|
|
2274
|
0
|
|
|
|
|
|
croak("must supply a code reference"); |
2275
|
10
|
50
|
|
|
|
|
if (unlikely(shutting_down)) |
2276
|
0
|
|
|
|
|
|
croak("already shutting down"); |
2277
|
10
|
|
|
|
|
|
shutdown_cb_cv = newSVsv(cb); |
2278
|
|
|
|
|
|
|
trace("shutting down, handler=%p, active=%d\n", SvRV(cb), active_conns); |
2279
|
|
|
|
|
|
|
|
2280
|
10
|
|
|
|
|
|
shutting_down = 1; |
2281
|
10
|
|
|
|
|
|
ev_io_stop(feersum_ev_loop, &accept_w); |
2282
|
10
|
|
|
|
|
|
close(accept_w.fd); |
2283
|
|
|
|
|
|
|
|
2284
|
10
|
100
|
|
|
|
|
if (active_conns <= 0) { |
2285
|
|
|
|
|
|
|
trace("shutdown is immediate\n"); |
2286
|
9
|
|
|
|
|
|
dSP; |
2287
|
9
|
|
|
|
|
|
ENTER; |
2288
|
9
|
|
|
|
|
|
SAVETMPS; |
2289
|
9
|
50
|
|
|
|
|
PUSHMARK(SP); |
2290
|
9
|
|
|
|
|
|
call_sv(shutdown_cb_cv, G_EVAL|G_VOID|G_DISCARD|G_NOARGS|G_KEEPERR); |
2291
|
1
|
|
|
|
|
|
PUTBACK; |
2292
|
|
|
|
|
|
|
trace3("called shutdown handler\n"); |
2293
|
1
|
|
|
|
|
|
SvREFCNT_dec(shutdown_cb_cv); |
2294
|
1
|
|
|
|
|
|
shutdown_cb_cv = NULL; |
2295
|
1
|
50
|
|
|
|
|
FREETMPS; |
2296
|
1
|
|
|
|
|
|
LEAVE; |
2297
|
|
|
|
|
|
|
} |
2298
|
|
|
|
|
|
|
} |
2299
|
|
|
|
|
|
|
|
2300
|
|
|
|
|
|
|
double |
2301
|
|
|
|
|
|
|
read_timeout (SV *self, ...) |
2302
|
|
|
|
|
|
|
PROTOTYPE: $;$ |
2303
|
|
|
|
|
|
|
CODE: |
2304
|
|
|
|
|
|
|
{ |
2305
|
13
|
100
|
|
|
|
|
if (items <= 1) { |
2306
|
7
|
|
|
|
|
|
RETVAL = read_timeout; |
2307
|
|
|
|
|
|
|
} |
2308
|
6
|
50
|
|
|
|
|
else if (items == 2) { |
2309
|
6
|
|
|
|
|
|
SV *duration = ST(1); |
2310
|
6
|
100
|
|
|
|
|
NV new_read_timeout = SvNV(duration); |
2311
|
6
|
100
|
|
|
|
|
if (!(new_read_timeout > 0.0)) { |
2312
|
3
|
|
|
|
|
|
croak("must set a positive (non-zero) value for the timeout"); |
2313
|
|
|
|
|
|
|
} |
2314
|
3
|
|
|
|
|
|
read_timeout = (double) new_read_timeout; |
2315
|
|
|
|
|
|
|
} |
2316
|
|
|
|
|
|
|
} |
2317
|
|
|
|
|
|
|
OUTPUT: |
2318
|
|
|
|
|
|
|
RETVAL |
2319
|
|
|
|
|
|
|
|
2320
|
|
|
|
|
|
|
void |
2321
|
|
|
|
|
|
|
DESTROY (SV *self) |
2322
|
|
|
|
|
|
|
PPCODE: |
2323
|
|
|
|
|
|
|
{ |
2324
|
|
|
|
|
|
|
trace3("DESTROY server\n"); |
2325
|
29
|
50
|
|
|
|
|
if (request_cb_cv) |
2326
|
29
|
|
|
|
|
|
SvREFCNT_dec(request_cb_cv); |
2327
|
|
|
|
|
|
|
} |
2328
|
|
|
|
|
|
|
|
2329
|
|
|
|
|
|
|
MODULE = Feersum PACKAGE = Feersum::Connection::Handle |
2330
|
|
|
|
|
|
|
|
2331
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
2332
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
int |
2334
|
|
|
|
|
|
|
fileno (feer_conn_handle *hdl) |
2335
|
|
|
|
|
|
|
CODE: |
2336
|
0
|
|
|
|
|
|
RETVAL = c->fd; |
2337
|
|
|
|
|
|
|
OUTPUT: |
2338
|
|
|
|
|
|
|
RETVAL |
2339
|
|
|
|
|
|
|
|
2340
|
|
|
|
|
|
|
void |
2341
|
|
|
|
|
|
|
DESTROY (SV *self) |
2342
|
|
|
|
|
|
|
ALIAS: |
2343
|
|
|
|
|
|
|
Feersum::Connection::Reader::DESTROY = 1 |
2344
|
|
|
|
|
|
|
Feersum::Connection::Writer::DESTROY = 2 |
2345
|
|
|
|
|
|
|
PPCODE: |
2346
|
|
|
|
|
|
|
{ |
2347
|
28
|
|
|
|
|
|
feer_conn_handle *hdl = sv_2feer_conn_handle(self, 0); |
2348
|
|
|
|
|
|
|
|
2349
|
28
|
100
|
|
|
|
|
if (hdl == NULL) { |
2350
|
|
|
|
|
|
|
trace3("DESTROY handle (closed) class=%s\n", |
2351
|
|
|
|
|
|
|
HvNAME(SvSTASH(SvRV(self)))); |
2352
|
|
|
|
|
|
|
} |
2353
|
|
|
|
|
|
|
else { |
2354
|
11
|
|
|
|
|
|
struct feer_conn *c = (struct feer_conn *)hdl; |
2355
|
|
|
|
|
|
|
trace3("DESTROY handle fd=%d, class=%s\n", c->fd, |
2356
|
|
|
|
|
|
|
HvNAME(SvSTASH(SvRV(self)))); |
2357
|
11
|
100
|
|
|
|
|
if (ix == 2) // only close the writer on destruction |
2358
|
6
|
|
|
|
|
|
feersum_close_handle(aTHX_ c, 1); |
2359
|
|
|
|
|
|
|
} |
2360
|
|
|
|
|
|
|
} |
2361
|
|
|
|
|
|
|
|
2362
|
|
|
|
|
|
|
SV* |
2363
|
|
|
|
|
|
|
read (feer_conn_handle *hdl, SV *buf, size_t len, ...) |
2364
|
|
|
|
|
|
|
PROTOTYPE: $$$;$ |
2365
|
|
|
|
|
|
|
PPCODE: |
2366
|
|
|
|
|
|
|
{ |
2367
|
13
|
|
|
|
|
|
STRLEN buf_len = 0, src_len = 0; |
2368
|
|
|
|
|
|
|
ssize_t offset; |
2369
|
|
|
|
|
|
|
char *buf_ptr, *src_ptr; |
2370
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
// optimizes for the "read everything" case. |
2372
|
|
|
|
|
|
|
|
2373
|
13
|
100
|
|
|
|
|
if (unlikely(items == 4) && SvOK(ST(3)) && SvIOK(ST(3))) |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2374
|
4
|
50
|
|
|
|
|
offset = SvIV(ST(3)); |
2375
|
|
|
|
|
|
|
else |
2376
|
9
|
|
|
|
|
|
offset = 0; |
2377
|
|
|
|
|
|
|
|
2378
|
|
|
|
|
|
|
trace("read fd=%d : request len=%"Sz_uf" off=%"Ssz_df"\n", |
2379
|
|
|
|
|
|
|
c->fd, (Sz)len, (Ssz)offset); |
2380
|
|
|
|
|
|
|
|
2381
|
13
|
50
|
|
|
|
|
if (unlikely(c->receiving <= RECEIVE_HEADERS)) |
2382
|
|
|
|
|
|
|
// XXX as of 0.984 this is dead code |
2383
|
0
|
|
|
|
|
|
croak("can't call read() until the body begins to arrive"); |
2384
|
|
|
|
|
|
|
|
2385
|
13
|
100
|
|
|
|
|
if (!SvOK(buf) || !SvPOK(buf)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2386
|
|
|
|
|
|
|
// force to a PV and ensure buffer space |
2387
|
6
|
|
|
|
|
|
sv_setpvn(buf,"",0); |
2388
|
6
|
50
|
|
|
|
|
SvGROW(buf, len+1); |
|
|
100
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
} |
2390
|
|
|
|
|
|
|
|
2391
|
13
|
50
|
|
|
|
|
if (unlikely(SvREADONLY(buf))) |
2392
|
0
|
|
|
|
|
|
croak("buffer must not be read-only"); |
2393
|
|
|
|
|
|
|
|
2394
|
13
|
50
|
|
|
|
|
if (unlikely(len == 0)) |
2395
|
0
|
|
|
|
|
|
XSRETURN_IV(0); // assumes undef buffer got allocated to empty-string |
2396
|
|
|
|
|
|
|
|
2397
|
13
|
50
|
|
|
|
|
buf_ptr = SvPV(buf, buf_len); |
2398
|
13
|
100
|
|
|
|
|
if (likely(c->rbuf)) |
2399
|
13
|
50
|
|
|
|
|
src_ptr = SvPV(c->rbuf, src_len); |
2400
|
|
|
|
|
|
|
|
2401
|
|
|
|
|
|
|
if (unlikely(len < 0)) |
2402
|
|
|
|
|
|
|
len = src_len; |
2403
|
|
|
|
|
|
|
|
2404
|
13
|
100
|
|
|
|
|
if (unlikely(offset < 0)) |
2405
|
1
|
50
|
|
|
|
|
offset = (-offset >= c->received_cl) ? 0 : c->received_cl + offset; |
2406
|
|
|
|
|
|
|
|
2407
|
13
|
100
|
|
|
|
|
if (unlikely(len + offset > src_len)) |
2408
|
4
|
|
|
|
|
|
len = src_len - offset; |
2409
|
|
|
|
|
|
|
|
2410
|
|
|
|
|
|
|
trace("read fd=%d : normalized len=%"Sz_uf" off=%"Ssz_df" src_len=%"Sz_uf"\n", |
2411
|
|
|
|
|
|
|
c->fd, (Sz)len, (Ssz)offset, (Sz)src_len); |
2412
|
|
|
|
|
|
|
|
2413
|
13
|
100
|
|
|
|
|
if (unlikely(!c->rbuf || src_len == 0 || offset >= c->received_cl)) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2414
|
|
|
|
|
|
|
trace2("rbuf empty during read %d\n", c->fd); |
2415
|
2
|
50
|
|
|
|
|
if (c->receiving == RECEIVE_SHUTDOWN) { |
2416
|
2
|
|
|
|
|
|
XSRETURN_IV(0); |
2417
|
|
|
|
|
|
|
} |
2418
|
|
|
|
|
|
|
else { |
2419
|
0
|
|
|
|
|
|
errno = EAGAIN; |
2420
|
0
|
|
|
|
|
|
XSRETURN_UNDEF; |
2421
|
|
|
|
|
|
|
} |
2422
|
|
|
|
|
|
|
} |
2423
|
|
|
|
|
|
|
|
2424
|
11
|
100
|
|
|
|
|
if (likely(len == src_len && offset == 0)) { |
|
|
50
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
trace2("appending entire rbuf fd=%d\n", c->fd); |
2426
|
6
|
|
|
|
|
|
sv_2mortal(c->rbuf); // allow pv to be stolen |
2427
|
6
|
100
|
|
|
|
|
if (likely(buf_len == 0)) { |
2428
|
4
|
|
|
|
|
|
sv_setsv(buf, c->rbuf); |
2429
|
|
|
|
|
|
|
} |
2430
|
|
|
|
|
|
|
else { |
2431
|
2
|
|
|
|
|
|
sv_catsv(buf, c->rbuf); |
2432
|
|
|
|
|
|
|
} |
2433
|
6
|
|
|
|
|
|
c->rbuf = NULL; |
2434
|
|
|
|
|
|
|
} |
2435
|
|
|
|
|
|
|
else { |
2436
|
5
|
|
|
|
|
|
src_ptr += offset; |
2437
|
|
|
|
|
|
|
trace2("appending partial rbuf fd=%d len=%"Sz_uf" off=%"Ssz_df" ptr=%p\n", |
2438
|
|
|
|
|
|
|
c->fd, len, offset, src_ptr); |
2439
|
5
|
50
|
|
|
|
|
SvGROW(buf, SvCUR(buf) + len); |
|
|
50
|
|
|
|
|
|
2440
|
5
|
|
|
|
|
|
sv_catpvn(buf, src_ptr, len); |
2441
|
5
|
100
|
|
|
|
|
if (likely(items == 3)) { |
2442
|
|
|
|
|
|
|
// there wasn't an offset param, throw away beginning |
2443
|
3
|
|
|
|
|
|
sv_chop(c->rbuf, SvPVX(c->rbuf) + len); |
2444
|
|
|
|
|
|
|
} |
2445
|
|
|
|
|
|
|
} |
2446
|
|
|
|
|
|
|
|
2447
|
13
|
|
|
|
|
|
XSRETURN_IV(len); |
2448
|
|
|
|
|
|
|
} |
2449
|
|
|
|
|
|
|
|
2450
|
|
|
|
|
|
|
STRLEN |
2451
|
|
|
|
|
|
|
write (feer_conn_handle *hdl, ...) |
2452
|
|
|
|
|
|
|
PROTOTYPE: $;$ |
2453
|
|
|
|
|
|
|
CODE: |
2454
|
|
|
|
|
|
|
{ |
2455
|
24
|
50
|
|
|
|
|
if (unlikely(c->responding != RESPOND_STREAMING)) |
2456
|
0
|
|
|
|
|
|
croak("can only call write in streaming mode"); |
2457
|
|
|
|
|
|
|
|
2458
|
24
|
50
|
|
|
|
|
SV *body = (items == 2) ? ST(1) : &PL_sv_undef; |
2459
|
24
|
50
|
|
|
|
|
if (unlikely(!body || !SvOK(body))) |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2460
|
0
|
|
|
|
|
|
XSRETURN_IV(0); |
2461
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
trace("write fd=%d c=%p, body=%p\n", c->fd, c, body); |
2463
|
24
|
50
|
|
|
|
|
if (SvROK(body)) { |
2464
|
0
|
|
|
|
|
|
SV *refd = SvRV(body); |
2465
|
0
|
0
|
|
|
|
|
if (SvOK(refd) && SvPOK(refd)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2466
|
0
|
|
|
|
|
|
body = refd; |
2467
|
|
|
|
|
|
|
} |
2468
|
|
|
|
|
|
|
else { |
2469
|
0
|
|
|
|
|
|
croak("body must be a scalar, scalar ref or undef"); |
2470
|
|
|
|
|
|
|
} |
2471
|
|
|
|
|
|
|
} |
2472
|
24
|
50
|
|
|
|
|
(void)SvPV(body, RETVAL); |
2473
|
|
|
|
|
|
|
|
2474
|
24
|
100
|
|
|
|
|
if (c->is_http11) |
2475
|
15
|
|
|
|
|
|
add_chunk_sv_to_wbuf(c, body); |
2476
|
|
|
|
|
|
|
else |
2477
|
9
|
|
|
|
|
|
add_sv_to_wbuf(c, body); |
2478
|
|
|
|
|
|
|
|
2479
|
24
|
|
|
|
|
|
conn_write_ready(c); |
2480
|
|
|
|
|
|
|
} |
2481
|
|
|
|
|
|
|
OUTPUT: |
2482
|
|
|
|
|
|
|
RETVAL |
2483
|
|
|
|
|
|
|
|
2484
|
|
|
|
|
|
|
void |
2485
|
|
|
|
|
|
|
write_array (feer_conn_handle *hdl, AV *abody) |
2486
|
|
|
|
|
|
|
PROTOTYPE: $$ |
2487
|
|
|
|
|
|
|
PPCODE: |
2488
|
|
|
|
|
|
|
{ |
2489
|
2
|
50
|
|
|
|
|
if (unlikely(c->responding != RESPOND_STREAMING)) |
2490
|
0
|
|
|
|
|
|
croak("can only call write in streaming mode"); |
2491
|
|
|
|
|
|
|
|
2492
|
|
|
|
|
|
|
trace("write_array fd=%d c=%p, abody=%p\n", c->fd, c, abody); |
2493
|
|
|
|
|
|
|
|
2494
|
2
|
|
|
|
|
|
I32 amax = av_len(abody); |
2495
|
|
|
|
|
|
|
int i; |
2496
|
2
|
50
|
|
|
|
|
if (c->is_http11) { |
2497
|
12
|
100
|
|
|
|
|
for (i=0; i<=amax; i++) { |
2498
|
10
|
|
|
|
|
|
SV *sv = fetch_av_normal(aTHX_ abody, i); |
2499
|
10
|
100
|
|
|
|
|
if (likely(sv)) add_chunk_sv_to_wbuf(c, sv); |
2500
|
|
|
|
|
|
|
} |
2501
|
|
|
|
|
|
|
} |
2502
|
|
|
|
|
|
|
else { |
2503
|
0
|
0
|
|
|
|
|
for (i=0; i<=amax; i++) { |
2504
|
0
|
|
|
|
|
|
SV *sv = fetch_av_normal(aTHX_ abody, i); |
2505
|
0
|
0
|
|
|
|
|
if (likely(sv)) add_sv_to_wbuf(c, sv); |
2506
|
|
|
|
|
|
|
} |
2507
|
|
|
|
|
|
|
} |
2508
|
|
|
|
|
|
|
|
2509
|
2
|
|
|
|
|
|
conn_write_ready(c); |
2510
|
|
|
|
|
|
|
} |
2511
|
|
|
|
|
|
|
|
2512
|
|
|
|
|
|
|
int |
2513
|
|
|
|
|
|
|
seek (feer_conn_handle *hdl, ssize_t offset, ...) |
2514
|
|
|
|
|
|
|
PROTOTYPE: $$;$ |
2515
|
|
|
|
|
|
|
CODE: |
2516
|
|
|
|
|
|
|
{ |
2517
|
9
|
|
|
|
|
|
int whence = SEEK_CUR; |
2518
|
9
|
50
|
|
|
|
|
if (items == 3 && SvOK(ST(2)) && SvIOK(ST(2))) |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2519
|
9
|
50
|
|
|
|
|
whence = SvIV(ST(2)); |
2520
|
|
|
|
|
|
|
|
2521
|
|
|
|
|
|
|
trace("seek fd=%d offset=%"Ssz_df" whence=%d\n", c->fd, offset, whence); |
2522
|
|
|
|
|
|
|
|
2523
|
9
|
100
|
|
|
|
|
if (unlikely(!c->rbuf)) { |
2524
|
|
|
|
|
|
|
// handle is effectively "closed" |
2525
|
1
|
|
|
|
|
|
RETVAL = 0; |
2526
|
|
|
|
|
|
|
} |
2527
|
8
|
100
|
|
|
|
|
else if (offset == 0) { |
2528
|
2
|
|
|
|
|
|
RETVAL = 1; // stay put for any whence |
2529
|
|
|
|
|
|
|
} |
2530
|
8
|
100
|
|
|
|
|
else if (offset > 0 && (whence == SEEK_CUR || whence == SEEK_SET)) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2531
|
|
|
|
|
|
|
STRLEN len; |
2532
|
2
|
50
|
|
|
|
|
const char *str = SvPV_const(c->rbuf, len); |
2533
|
2
|
50
|
|
|
|
|
if (offset > len) |
2534
|
0
|
|
|
|
|
|
offset = len; |
2535
|
2
|
|
|
|
|
|
sv_chop(c->rbuf, str + offset); |
2536
|
2
|
|
|
|
|
|
RETVAL = 1; |
2537
|
|
|
|
|
|
|
} |
2538
|
6
|
50
|
|
|
|
|
else if (offset < 0 && whence == SEEK_END) { |
|
|
100
|
|
|
|
|
|
2539
|
|
|
|
|
|
|
STRLEN len; |
2540
|
2
|
50
|
|
|
|
|
const char *str = SvPV_const(c->rbuf, len); |
2541
|
2
|
|
|
|
|
|
offset += len; // can't be > len since block is offset<0 |
2542
|
2
|
50
|
|
|
|
|
if (offset == 0) { |
2543
|
0
|
|
|
|
|
|
RETVAL = 1; // no-op, but OK |
2544
|
|
|
|
|
|
|
} |
2545
|
2
|
100
|
|
|
|
|
else if (offset > 0) { |
2546
|
1
|
|
|
|
|
|
sv_chop(c->rbuf, str + offset); |
2547
|
1
|
|
|
|
|
|
RETVAL = 1; |
2548
|
|
|
|
|
|
|
} |
2549
|
|
|
|
|
|
|
else { |
2550
|
|
|
|
|
|
|
// past beginning of string |
2551
|
1
|
|
|
|
|
|
RETVAL = 0; |
2552
|
|
|
|
|
|
|
} |
2553
|
|
|
|
|
|
|
} |
2554
|
|
|
|
|
|
|
else { |
2555
|
|
|
|
|
|
|
// invalid seek |
2556
|
2
|
|
|
|
|
|
RETVAL = 0; |
2557
|
|
|
|
|
|
|
} |
2558
|
|
|
|
|
|
|
} |
2559
|
|
|
|
|
|
|
OUTPUT: |
2560
|
|
|
|
|
|
|
RETVAL |
2561
|
|
|
|
|
|
|
|
2562
|
|
|
|
|
|
|
int |
2563
|
|
|
|
|
|
|
close (feer_conn_handle *hdl) |
2564
|
|
|
|
|
|
|
PROTOTYPE: $ |
2565
|
|
|
|
|
|
|
ALIAS: |
2566
|
|
|
|
|
|
|
Feersum::Connection::Reader::close = 1 |
2567
|
|
|
|
|
|
|
Feersum::Connection::Writer::close = 2 |
2568
|
|
|
|
|
|
|
CODE: |
2569
|
|
|
|
|
|
|
{ |
2570
|
|
|
|
|
|
|
assert(ix); |
2571
|
17
|
|
|
|
|
|
RETVAL = feersum_close_handle(aTHX_ c, (ix == 2)); |
2572
|
17
|
|
|
|
|
|
SvUVX(hdl_sv) = 0; |
2573
|
|
|
|
|
|
|
} |
2574
|
|
|
|
|
|
|
OUTPUT: |
2575
|
|
|
|
|
|
|
RETVAL |
2576
|
|
|
|
|
|
|
|
2577
|
|
|
|
|
|
|
void |
2578
|
|
|
|
|
|
|
_poll_cb (feer_conn_handle *hdl, SV *cb) |
2579
|
|
|
|
|
|
|
PROTOTYPE: $$ |
2580
|
|
|
|
|
|
|
ALIAS: |
2581
|
|
|
|
|
|
|
Feersum::Connection::Reader::poll_cb = 1 |
2582
|
|
|
|
|
|
|
Feersum::Connection::Writer::poll_cb = 2 |
2583
|
|
|
|
|
|
|
PPCODE: |
2584
|
|
|
|
|
|
|
{ |
2585
|
8
|
50
|
|
|
|
|
if (unlikely(ix < 1 || ix > 2)) |
|
|
50
|
|
|
|
|
|
2586
|
0
|
|
|
|
|
|
croak("can't call _poll_cb directly"); |
2587
|
8
|
50
|
|
|
|
|
else if (unlikely(ix == 1)) |
2588
|
0
|
|
|
|
|
|
croak("poll_cb for reading not yet supported"); // TODO poll_read_cb |
2589
|
|
|
|
|
|
|
|
2590
|
8
|
100
|
|
|
|
|
if (c->poll_write_cb != NULL) { |
2591
|
4
|
|
|
|
|
|
SvREFCNT_dec(c->poll_write_cb); |
2592
|
4
|
|
|
|
|
|
c->poll_write_cb = NULL; |
2593
|
|
|
|
|
|
|
} |
2594
|
|
|
|
|
|
|
|
2595
|
8
|
100
|
|
|
|
|
if (!SvOK(cb)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2596
|
|
|
|
|
|
|
trace("unset poll_cb ix=%d\n", ix); |
2597
|
4
|
|
|
|
|
|
return; |
2598
|
|
|
|
|
|
|
} |
2599
|
4
|
50
|
|
|
|
|
else if (unlikely(!IsCodeRef(cb))) |
|
|
50
|
|
|
|
|
|
2600
|
0
|
|
|
|
|
|
croak("must supply a code reference to poll_cb"); |
2601
|
|
|
|
|
|
|
|
2602
|
4
|
|
|
|
|
|
c->poll_write_cb = newSVsv(cb); |
2603
|
4
|
|
|
|
|
|
conn_write_ready(c); |
2604
|
|
|
|
|
|
|
} |
2605
|
|
|
|
|
|
|
|
2606
|
|
|
|
|
|
|
SV* |
2607
|
|
|
|
|
|
|
response_guard (feer_conn_handle *hdl, ...) |
2608
|
|
|
|
|
|
|
PROTOTYPE: $;$ |
2609
|
|
|
|
|
|
|
CODE: |
2610
|
3
|
100
|
|
|
|
|
RETVAL = feersum_conn_guard(aTHX_ c, (items==2) ? ST(1) : NULL); |
2611
|
|
|
|
|
|
|
OUTPUT: |
2612
|
|
|
|
|
|
|
RETVAL |
2613
|
|
|
|
|
|
|
|
2614
|
|
|
|
|
|
|
MODULE = Feersum PACKAGE = Feersum::Connection |
2615
|
|
|
|
|
|
|
|
2616
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
2617
|
|
|
|
|
|
|
|
2618
|
|
|
|
|
|
|
SV * |
2619
|
|
|
|
|
|
|
start_streaming (struct feer_conn *c, SV *message, AV *headers) |
2620
|
|
|
|
|
|
|
PROTOTYPE: $$\@ |
2621
|
|
|
|
|
|
|
CODE: |
2622
|
12
|
|
|
|
|
|
feersum_start_response(aTHX_ c, message, headers, 1); |
2623
|
12
|
|
|
|
|
|
RETVAL = new_feer_conn_handle(aTHX_ c, 1); // RETVAL gets mortalized |
2624
|
|
|
|
|
|
|
OUTPUT: |
2625
|
|
|
|
|
|
|
RETVAL |
2626
|
|
|
|
|
|
|
|
2627
|
|
|
|
|
|
|
size_t |
2628
|
|
|
|
|
|
|
send_response (struct feer_conn *c, SV* message, AV *headers, SV *body) |
2629
|
|
|
|
|
|
|
PROTOTYPE: $$\@$ |
2630
|
|
|
|
|
|
|
CODE: |
2631
|
22
|
|
|
|
|
|
feersum_start_response(aTHX_ c, message, headers, 0); |
2632
|
22
|
50
|
|
|
|
|
if (unlikely(!SvOK(body))) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2633
|
0
|
|
|
|
|
|
croak("can't send_response with an undef body"); |
2634
|
22
|
|
|
|
|
|
RETVAL = feersum_write_whole_body(aTHX_ c, body); |
2635
|
|
|
|
|
|
|
OUTPUT: |
2636
|
|
|
|
|
|
|
RETVAL |
2637
|
|
|
|
|
|
|
|
2638
|
|
|
|
|
|
|
SV* |
2639
|
|
|
|
|
|
|
_continue_streaming_psgi (struct feer_conn *c, SV *psgi_response) |
2640
|
|
|
|
|
|
|
PROTOTYPE: $\@ |
2641
|
|
|
|
|
|
|
CODE: |
2642
|
|
|
|
|
|
|
{ |
2643
|
|
|
|
|
|
|
AV *av; |
2644
|
9
|
|
|
|
|
|
int len = 0; |
2645
|
|
|
|
|
|
|
|
2646
|
9
|
50
|
|
|
|
|
if (IsArrayRef(psgi_response)) { |
|
|
50
|
|
|
|
|
|
2647
|
9
|
|
|
|
|
|
av = (AV*)SvRV(psgi_response); |
2648
|
9
|
|
|
|
|
|
len = av_len(av) + 1; |
2649
|
|
|
|
|
|
|
} |
2650
|
|
|
|
|
|
|
|
2651
|
9
|
100
|
|
|
|
|
if (len == 3) { |
2652
|
|
|
|
|
|
|
// 0 is "don't recurse" (i.e. don't allow another code-ref) |
2653
|
6
|
|
|
|
|
|
feersum_handle_psgi_response(aTHX_ c, psgi_response, 0); |
2654
|
6
|
|
|
|
|
|
RETVAL = &PL_sv_undef; |
2655
|
|
|
|
|
|
|
} |
2656
|
3
|
50
|
|
|
|
|
else if (len == 2) { |
2657
|
3
|
|
|
|
|
|
SV *message = *(av_fetch(av,0,0)); |
2658
|
3
|
|
|
|
|
|
SV *headers = *(av_fetch(av,1,0)); |
2659
|
3
|
50
|
|
|
|
|
if (unlikely(!IsArrayRef(headers))) |
|
|
50
|
|
|
|
|
|
2660
|
0
|
|
|
|
|
|
croak("PSGI headers must be an array ref"); |
2661
|
3
|
|
|
|
|
|
feersum_start_response(aTHX_ c, message, (AV*)SvRV(headers), 1); |
2662
|
3
|
|
|
|
|
|
RETVAL = new_feer_conn_handle(aTHX_ c, 1); // RETVAL gets mortalized |
2663
|
|
|
|
|
|
|
} |
2664
|
|
|
|
|
|
|
else { |
2665
|
0
|
|
|
|
|
|
croak("PSGI response starter expects a 2 or 3 element array-ref"); |
2666
|
|
|
|
|
|
|
} |
2667
|
|
|
|
|
|
|
} |
2668
|
|
|
|
|
|
|
OUTPUT: |
2669
|
|
|
|
|
|
|
RETVAL |
2670
|
|
|
|
|
|
|
|
2671
|
|
|
|
|
|
|
void |
2672
|
|
|
|
|
|
|
force_http10 (struct feer_conn *c) |
2673
|
|
|
|
|
|
|
PROTOTYPE: $ |
2674
|
|
|
|
|
|
|
ALIAS: |
2675
|
|
|
|
|
|
|
force_http11 = 1 |
2676
|
|
|
|
|
|
|
PPCODE: |
2677
|
0
|
|
|
|
|
|
c->is_http11 = ix; |
2678
|
|
|
|
|
|
|
|
2679
|
|
|
|
|
|
|
SV * |
2680
|
|
|
|
|
|
|
env (struct feer_conn *c) |
2681
|
|
|
|
|
|
|
PROTOTYPE: $ |
2682
|
|
|
|
|
|
|
CODE: |
2683
|
26
|
|
|
|
|
|
RETVAL = newRV_noinc((SV*)feersum_env(aTHX_ c)); |
2684
|
|
|
|
|
|
|
OUTPUT: |
2685
|
|
|
|
|
|
|
RETVAL |
2686
|
|
|
|
|
|
|
|
2687
|
|
|
|
|
|
|
int |
2688
|
|
|
|
|
|
|
fileno (struct feer_conn *c) |
2689
|
|
|
|
|
|
|
CODE: |
2690
|
6
|
|
|
|
|
|
RETVAL = c->fd; |
2691
|
|
|
|
|
|
|
OUTPUT: |
2692
|
|
|
|
|
|
|
RETVAL |
2693
|
|
|
|
|
|
|
|
2694
|
|
|
|
|
|
|
SV* |
2695
|
|
|
|
|
|
|
response_guard (struct feer_conn *c, ...) |
2696
|
|
|
|
|
|
|
PROTOTYPE: $;$ |
2697
|
|
|
|
|
|
|
CODE: |
2698
|
3
|
100
|
|
|
|
|
RETVAL = feersum_conn_guard(aTHX_ c, (items == 2) ? ST(1) : NULL); |
2699
|
|
|
|
|
|
|
OUTPUT: |
2700
|
|
|
|
|
|
|
RETVAL |
2701
|
|
|
|
|
|
|
|
2702
|
|
|
|
|
|
|
void |
2703
|
|
|
|
|
|
|
DESTROY (struct feer_conn *c) |
2704
|
|
|
|
|
|
|
PPCODE: |
2705
|
|
|
|
|
|
|
{ |
2706
|
|
|
|
|
|
|
int i; |
2707
|
|
|
|
|
|
|
trace("DESTROY connection fd=%d c=%p\n", c->fd, c); |
2708
|
|
|
|
|
|
|
|
2709
|
118
|
100
|
|
|
|
|
if (likely(c->rbuf)) SvREFCNT_dec(c->rbuf); |
2710
|
|
|
|
|
|
|
|
2711
|
118
|
50
|
|
|
|
|
if (c->wbuf_rinq) { |
2712
|
|
|
|
|
|
|
struct iomatrix *m; |
2713
|
0
|
0
|
|
|
|
|
while ((m = (struct iomatrix *)rinq_shift(&c->wbuf_rinq)) != NULL) { |
2714
|
0
|
0
|
|
|
|
|
for (i=0; i < m->count; i++) { |
2715
|
0
|
0
|
|
|
|
|
if (m->sv[i]) SvREFCNT_dec(m->sv[i]); |
2716
|
|
|
|
|
|
|
} |
2717
|
0
|
|
|
|
|
|
Safefree(m); |
2718
|
|
|
|
|
|
|
} |
2719
|
|
|
|
|
|
|
} |
2720
|
|
|
|
|
|
|
|
2721
|
118
|
100
|
|
|
|
|
if (likely(c->req)) { |
2722
|
111
|
100
|
|
|
|
|
if (c->req->buf) SvREFCNT_dec(c->req->buf); |
2723
|
111
|
|
|
|
|
|
Safefree(c->req); |
2724
|
|
|
|
|
|
|
} |
2725
|
|
|
|
|
|
|
|
2726
|
118
|
50
|
|
|
|
|
if (likely(c->sa)) free(c->sa); |
2727
|
|
|
|
|
|
|
|
2728
|
118
|
|
|
|
|
|
safe_close_conn(c, "close at destruction"); |
2729
|
|
|
|
|
|
|
|
2730
|
118
|
50
|
|
|
|
|
if (c->poll_write_cb) SvREFCNT_dec(c->poll_write_cb); |
2731
|
|
|
|
|
|
|
|
2732
|
118
|
100
|
|
|
|
|
if (c->ext_guard) SvREFCNT_dec(c->ext_guard); |
2733
|
|
|
|
|
|
|
|
2734
|
118
|
|
|
|
|
|
active_conns--; |
2735
|
|
|
|
|
|
|
|
2736
|
118
|
100
|
|
|
|
|
if (unlikely(shutting_down && active_conns <= 0)) { |
|
|
100
|
|
|
|
|
|
2737
|
1
|
|
|
|
|
|
ev_idle_stop(feersum_ev_loop, &ei); |
2738
|
1
|
|
|
|
|
|
ev_prepare_stop(feersum_ev_loop, &ep); |
2739
|
1
|
|
|
|
|
|
ev_check_stop(feersum_ev_loop, &ec); |
2740
|
|
|
|
|
|
|
|
2741
|
|
|
|
|
|
|
trace3("... was last conn, going to try shutdown\n"); |
2742
|
1
|
50
|
|
|
|
|
if (shutdown_cb_cv) { |
2743
|
1
|
50
|
|
|
|
|
PUSHMARK(SP); |
2744
|
1
|
|
|
|
|
|
call_sv(shutdown_cb_cv, G_EVAL|G_VOID|G_DISCARD|G_NOARGS|G_KEEPERR); |
2745
|
1
|
|
|
|
|
|
PUTBACK; |
2746
|
|
|
|
|
|
|
trace3("... ok, called that handler\n"); |
2747
|
1
|
|
|
|
|
|
SvREFCNT_dec(shutdown_cb_cv); |
2748
|
1
|
|
|
|
|
|
shutdown_cb_cv = NULL; |
2749
|
|
|
|
|
|
|
} |
2750
|
|
|
|
|
|
|
} |
2751
|
|
|
|
|
|
|
} |
2752
|
|
|
|
|
|
|
|
2753
|
|
|
|
|
|
|
MODULE = Feersum PACKAGE = Feersum |
2754
|
|
|
|
|
|
|
|
2755
|
|
|
|
|
|
|
BOOT: |
2756
|
|
|
|
|
|
|
{ |
2757
|
32
|
|
|
|
|
|
feer_stash = gv_stashpv("Feersum", 1); |
2758
|
32
|
|
|
|
|
|
feer_conn_stash = gv_stashpv("Feersum::Connection", 1); |
2759
|
32
|
|
|
|
|
|
feer_conn_writer_stash = gv_stashpv("Feersum::Connection::Writer",0); |
2760
|
32
|
|
|
|
|
|
feer_conn_reader_stash = gv_stashpv("Feersum::Connection::Reader",0); |
2761
|
32
|
50
|
|
|
|
|
I_EV_API("Feersum"); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
2762
|
|
|
|
|
|
|
|
2763
|
32
|
|
|
|
|
|
psgi_ver = newAV(); |
2764
|
32
|
|
|
|
|
|
av_extend(psgi_ver, 2); |
2765
|
32
|
|
|
|
|
|
av_push(psgi_ver, newSViv(1)); |
2766
|
32
|
|
|
|
|
|
av_push(psgi_ver, newSViv(1)); |
2767
|
32
|
|
|
|
|
|
SvREADONLY_on((SV*)psgi_ver); |
2768
|
|
|
|
|
|
|
|
2769
|
32
|
|
|
|
|
|
psgi_serv10 = newSVpvs("HTTP/1.0"); |
2770
|
32
|
|
|
|
|
|
SvREADONLY_on(psgi_serv10); |
2771
|
32
|
|
|
|
|
|
psgi_serv11 = newSVpvs("HTTP/1.1"); |
2772
|
32
|
|
|
|
|
|
SvREADONLY_on(psgi_serv11); |
2773
|
|
|
|
|
|
|
|
2774
|
32
|
|
|
|
|
|
Zero(&psgix_io_vtbl, 1, MGVTBL); |
2775
|
32
|
|
|
|
|
|
psgix_io_vtbl.svt_get = psgix_io_svt_get; |
2776
|
|
|
|
|
|
|
|
2777
|
|
|
|
|
|
|
trace3("Feersum booted, iomatrix %lu " |
2778
|
|
|
|
|
|
|
"(IOV_MAX=%u, FEERSUM_IOMATRIX_SIZE=%u), " |
2779
|
|
|
|
|
|
|
"feer_req %lu, " |
2780
|
|
|
|
|
|
|
"feer_conn %lu\n", |
2781
|
|
|
|
|
|
|
(long unsigned int)sizeof(struct iomatrix), |
2782
|
|
|
|
|
|
|
(unsigned int)IOV_MAX, |
2783
|
|
|
|
|
|
|
(unsigned int)FEERSUM_IOMATRIX_SIZE, |
2784
|
|
|
|
|
|
|
(long unsigned int)sizeof(struct feer_req), |
2785
|
|
|
|
|
|
|
(long unsigned int)sizeof(struct feer_conn) |
2786
|
|
|
|
|
|
|
); |
2787
|
|
|
|
|
|
|
} |