File Coverage

Feersum.xs
Criterion Covered Total %
statement 1088 1412 77.0
branch 555 944 58.7
condition n/a
subroutine n/a
pod n/a
total 1643 2356 69.7


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