1 #ifdef __cplusplus
2 extern "C" {
3 #endif
4 
5 #define PERL_NO_GET_CONTEXT /* we want efficiency */
6 #include <EXTERN.h>
7 #include <perl.h>
8 #include <XSUB.h>
9 #include <poll.h>
10 #include <perlio.h>
11 
12 #ifdef __cplusplus
13 } /* extern "C" */
14 #endif
15 
16 #define NEED_newSVpvn_flags
17 
18 #include "ppport.h"
19 #ifndef __need_IOV_MAX
20 #define __need_IOV_MAX
21 #endif
22 
23 #include <sys/uio.h>
24 #include <errno.h>
25 #include <limits.h>
26 
27 #include <sys/types.h>
28 #define _GNU_SOURCE             /* See feature_test_macros(7) */
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
32 #include "picohttpparser/picohttpparser.c"
33 
34 #ifndef STATIC_INLINE /* a public perl API from 5.13.4 */
35 #   if defined(__GNUC__) || defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
36 #       define STATIC_INLINE static inline
37 #   else
38 #       define STATIC_INLINE static
39 #   endif
40 #endif /* STATIC_INLINE */
41 
42 #ifndef IOV_MAX
43 #if defined(__FreeBSD__) || defined(__APPLE__)
44 # define IOV_MAX 128
45 #endif
46 #endif
47 
48 #ifndef IOV_MAX
49 #  error "Unable to determine IOV_MAX from system headers"
50 #endif
51 
52 
53 #define MAX_HEADER_SIZE 16384
54 #define MAX_HEADER_NAME_LEN 1024
55 #define MAX_HEADERS         128
56 #if defined(__OpenBSD__)
57 #define READ_BUFSZ 16383
58 #else
59 #define READ_BUFSZ 16384
60 #endif
61 #define BAD_REQUEST "HTTP/1.0 400 Bad Request\r\nConnection: close\r\n\r\n400 Bad Request\r\n"
62 #define EXPECT_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
63 #define EXPECT_FAILED "HTTP/1.1 417 Expectation Failed\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nExpectation Failed\r\n"
64 #define TOU(ch) (('a' <= ch && ch <= 'z') ? ch - ('a' - 'A') : ch)
65 
66 static const char *DoW[] = {
67   "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
68 };
69 static const char *MoY[] = {
70   "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
71 };
72 static const char xdigit[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
73 
74 static HV *env_template;
75 
76 /* stolen from HTTP::Status and Feersum */
77 /* Unmarked codes are from RFC 2616 */
78 /* See also: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes */
79 static const char *
status_message(int code)80 status_message (int code) {
81   switch (code) {
82     case 100: return "Continue";
83     case 101: return "Switching Protocols";
84     case 102: return "Processing";                      /* RFC 2518 (WebDAV) */
85     case 200: return "OK";
86     case 201: return "Created";
87     case 202: return "Accepted";
88     case 203: return "Non-Authoritative Information";
89     case 204: return "No Content";
90     case 205: return "Reset Content";
91     case 206: return "Partial Content";
92     case 207: return "Multi-Status";                    /* RFC 2518 (WebDAV) */
93     case 208: return "Already Reported";              /* RFC 5842 */
94     case 300: return "Multiple Choices";
95     case 301: return "Moved Permanently";
96     case 302: return "Found";
97     case 303: return "See Other";
98     case 304: return "Not Modified";
99     case 305: return "Use Proxy";
100     case 307: return "Temporary Redirect";
101     case 400: return "Bad Request";
102     case 401: return "Unauthorized";
103     case 402: return "Payment Required";
104     case 403: return "Forbidden";
105     case 404: return "Not Found";
106     case 405: return "Method Not Allowed";
107     case 406: return "Not Acceptable";
108     case 407: return "Proxy Authentication Required";
109     case 408: return "Request Timeout";
110     case 409: return "Conflict";
111     case 410: return "Gone";
112     case 411: return "Length Required";
113     case 412: return "Precondition Failed";
114     case 413: return "Request Entity Too Large";
115     case 414: return "Request-URI Too Large";
116     case 415: return "Unsupported Media Type";
117     case 416: return "Request Range Not Satisfiable";
118     case 417: return "Expectation Failed";
119     case 418: return "I'm a teapot";              /* RFC 2324 */
120     case 422: return "Unprocessable Entity";            /* RFC 2518 (WebDAV) */
121     case 423: return "Locked";                          /* RFC 2518 (WebDAV) */
122     case 424: return "Failed Dependency";               /* RFC 2518 (WebDAV) */
123     case 425: return "No code";                         /* WebDAV Advanced Collections */
124     case 426: return "Upgrade Required";                /* RFC 2817 */
125     case 428: return "Precondition Required";
126     case 429: return "Too Many Requests";
127     case 431: return "Request Header Fields Too Large";
128     case 449: return "Retry with";                      /* unofficial Microsoft */
129     case 500: return "Internal Server Error";
130     case 501: return "Not Implemented";
131     case 502: return "Bad Gateway";
132     case 503: return "Service Unavailable";
133     case 504: return "Gateway Timeout";
134     case 505: return "HTTP Version Not Supported";
135     case 506: return "Variant Also Negotiates";         /* RFC 2295 */
136     case 507: return "Insufficient Storage";            /* RFC 2518 (WebDAV) */
137     case 509: return "Bandwidth Limit Exceeded";        /* unofficial */
138     case 510: return "Not Extended";                    /* RFC 2774 */
139     case 511: return "Network Authentication Required";
140     default: break;
141   }
142   /* default to the Nxx group names in RFC 2616 */
143   if (100 <= code && code <= 199) {
144     return "Informational";
145   }
146   else if (200 <= code && code <= 299) {
147     return "Success";
148     }
149     else if (300 <= code && code <= 399) {
150         return "Redirection";
151     }
152     else if (400 <= code && code <= 499) {
153         return "Client Error";
154     }
155     else {
156         return "Error";
157     }
158 }
159 
160 /* stolen from HTTP::Parser::XS */
161 static
find_ch(const char * s,size_t len,char ch)162 size_t find_ch(const char* s, size_t len, char ch)
163 {
164   size_t i;
165   for (i = 0; i != len; ++i, ++s)
166     if (*s == ch)
167       break;
168   return i;
169 }
170 
171 static
header_is(const struct phr_header * header,const char * name,size_t len)172 int header_is(const struct phr_header* header, const char* name,
173                     size_t len)
174 {
175   const char* x, * y;
176   if (header->name_len != len)
177     return 0;
178   for (x = header->name, y = name; len != 0; --len, ++x, ++y)
179     if (TOU(*x) != *y)
180       return 0;
181   return 1;
182 }
183 
184 
185 
186 STATIC_INLINE
store_path_info(pTHX_ HV * env,const char * src,size_t src_len)187 int store_path_info(pTHX_ HV* env, const char* src, size_t src_len) {
188   size_t dlen = 0, i = 0;
189   char *d;
190   char s2, s3;
191   SV * dst;
192 
193   dst = newSV(0);
194   (void)SvUPGRADE(dst, SVt_PV);
195   d = SvGROW(dst, src_len * 3 + 1);
196 
197   for (i = 0; i < src_len; i++ ) {
198     if ( src[i] == '%' ) {
199       if ( !isxdigit(src[i+1]) || !isxdigit(src[i+2]) ) {
200         return -1;
201       }
202       s2 = src[i+1];
203       s3 = src[i+2];
204       s2 -= s2 <= '9' ? '0'
205           : s2 <= 'F' ? 'A' - 10
206           : 'a' - 10;
207       s3 -= s3 <= '9' ? '0'
208           : s3 <= 'F' ? 'A' - 10
209           : 'a' - 10;
210        d[dlen++] = s2 * 16 + s3;
211        i += 2;
212     }
213     else {
214       d[dlen++] = src[i];
215     }
216   }
217   SvCUR_set(dst, dlen);
218   *SvEND(dst) = '\0';
219   SvPOK_only(dst);
220   (void)hv_stores(env, "PATH_INFO", dst);
221   return 1;
222 }
223 
224 
225 STATIC_INLINE
226 int
_parse_http_request(pTHX_ char * buf,ssize_t buf_len,HV * env)227 _parse_http_request(pTHX_ char *buf, ssize_t buf_len, HV *env) {
228   const char* method;
229   size_t method_len;
230   const char* path;
231   size_t path_len;
232   int minor_version;
233   struct phr_header headers[MAX_HEADERS];
234   size_t num_headers = MAX_HEADERS;
235   size_t question_at;
236   size_t i;
237   int ret;
238   SV* last_value;
239   char tmp[MAX_HEADER_NAME_LEN + sizeof("HTTP_") - 1];
240 
241   ret = phr_parse_request(
242     buf, buf_len,
243     &method, &method_len,
244     &path, &path_len,
245     &minor_version, headers, &num_headers, 0
246   );
247 
248   if (ret < 0)
249     goto done;
250   if (minor_version > 1 || minor_version < 0 ) {
251     ret = -1;
252     goto done;
253   }
254 
255   (void)hv_stores(env, "REQUEST_METHOD", newSVpvn(method, method_len));
256   (void)hv_stores(env, "REQUEST_URI", newSVpvn(path, path_len));
257   (void)hv_stores(env, "SCRIPT_NAME", newSVpvn("", 0));
258   strcpy(tmp, "HTTP/1.");
259   tmp[sizeof("HTTP/1.")-1] = '0' + minor_version;
260   (void)hv_stores(env, "SERVER_PROTOCOL", newSVpvn(tmp, sizeof("HTTP/1.1")-1));
261 
262   /* PATH_INFO QUERY_STRING */
263   path_len = find_ch(path, path_len, '#'); /* strip off all text after # after storing request_uri */
264   question_at = find_ch(path, path_len, '?');
265   if ( store_path_info(aTHX_ env, path, question_at) < 0 ) {
266     hv_clear(env);
267     ret = -1;
268     goto done;
269   }
270   if (question_at != path_len) ++question_at;
271   (void)hv_stores(env, "QUERY_STRING", newSVpvn(path + question_at, path_len - question_at));
272 
273   last_value = NULL;
274   for (i = 0; i < num_headers; ++i) {
275     if (headers[i].name != NULL) {
276       const char* name;
277       size_t name_len;
278       SV** slot;
279       if (header_is(headers + i, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1)) {
280         name = "CONTENT_TYPE";
281         name_len = sizeof("CONTENT_TYPE") - 1;
282       } else if (header_is(headers + i, "CONTENT-LENGTH", sizeof("CONTENT-LENGTH") - 1)) {
283         name = "CONTENT_LENGTH";
284         name_len = sizeof("CONTENT_LENGTH") - 1;
285       } else {
286         const char* s;
287         char* d;
288         size_t n;
289         if (sizeof(tmp) - 5 < headers[i].name_len) {
290           hv_clear(env);
291           ret = -1;
292           goto done;
293         }
294         strcpy(tmp, "HTTP_");
295         for (s = headers[i].name, n = headers[i].name_len, d = tmp + 5;
296           n != 0;
297           s++, --n, d++) {
298             *d = *s == '-' ? '_' : TOU(*s);
299             name = tmp;
300             name_len = headers[i].name_len + 5;
301         }
302       }
303       slot = hv_fetch(env, name, name_len, 1);
304       if ( !slot ) croak("ERROR: failed to create hash entry");
305       if (SvOK(*slot)) {
306         sv_catpvn(*slot, ", ", 2);
307         sv_catpvn(*slot, headers[i].value, headers[i].value_len);
308       } else {
309         sv_setpvn(*slot, headers[i].value, headers[i].value_len);
310         last_value = *slot;
311       }
312     } else {
313       /* continuing lines of a mulitiline header */
314       sv_catpvn(last_value, headers[i].value, headers[i].value_len);
315     }
316   }
317  done:
318   return ret;
319 }
320 
321 
322 STATIC_INLINE
323 char *
svpv2char(pTHX_ SV * sv,STRLEN * lp)324 svpv2char(pTHX_ SV *sv, STRLEN *lp)
325 {
326   if (SvGAMAGIC(sv))
327     sv = sv_2mortal(newSVsv(sv));
328   return SvPV(sv, *lp);
329 }
330 
331 
332 STATIC_INLINE
333 int
_accept(int fileno,struct sockaddr * addr,unsigned int addrlen)334 _accept(int fileno, struct sockaddr *addr, unsigned int addrlen) {
335     int fd;
336 #ifdef HAVE_ACCEPT4
337     fd = accept4(fileno, addr, &addrlen, SOCK_CLOEXEC|SOCK_NONBLOCK);
338 #else
339     fd = accept(fileno, addr, &addrlen);
340 #endif
341     if (fd < 0) {
342       return fd;
343     }
344 #ifndef HAVE_ACCEPT4
345     fcntl(fd, F_SETFD, FD_CLOEXEC);
346     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
347 #endif
348     return fd;
349 }
350 
351 
352 STATIC_INLINE
353 ssize_t
_writev_timeout(const int fileno,const double timeout,struct iovec * iovec,const int iovcnt,const int do_select)354 _writev_timeout(const int fileno, const double timeout, struct iovec *iovec, const int iovcnt, const int do_select ) {
355     int rv;
356     int nfound;
357     struct pollfd wfds[1];
358     if ( do_select == 1) goto WAIT_WRITE;
359   DO_WRITE:
360     rv = writev(fileno, iovec, iovcnt);
361     if ( rv >= 0 ) {
362       return rv;
363     }
364     if ( rv < 0 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK ) {
365       return rv;
366     }
367   WAIT_WRITE:
368     while (1) {
369       wfds[0].fd = fileno;
370       wfds[0].events = POLLOUT;
371       nfound = poll(wfds, 1, (int)timeout*1000);
372       if ( nfound == 1 ) {
373         break;
374       }
375       if ( nfound == 0 && errno != EINTR ) {
376         return -1;
377       }
378     }
379     goto DO_WRITE;
380 }
381 
382 STATIC_INLINE
383 ssize_t
_read_timeout(const int fileno,const double timeout,char * read_buf,const int read_len)384 _read_timeout(const int fileno, const double timeout, char * read_buf, const int read_len ) {
385     int rv;
386     int nfound;
387     struct pollfd rfds[1];
388   DO_READ:
389     rfds[0].fd = fileno;
390     rfds[0].events = POLLIN;
391     rv = read(fileno, read_buf, read_len);
392     if ( rv >= 0 ) {
393       return rv;
394     }
395     if ( rv < 0 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK ) {
396       return rv;
397     }
398   WAIT_READ:
399     while (1) {
400       nfound = poll(rfds, 1, (int)timeout*1000);
401       if ( nfound == 1 ) {
402         break;
403       }
404       if ( nfound == 0 && errno != EINTR ) {
405         return -1;
406       }
407     }
408     goto DO_READ;
409 }
410 
411 STATIC_INLINE
412 ssize_t
_write_timeout(const int fileno,const double timeout,char * write_buf,const int write_len)413 _write_timeout(const int fileno, const double timeout, char * write_buf, const int write_len ) {
414     int rv;
415     int nfound;
416     struct pollfd wfds[1];
417   DO_WRITE:
418     rv = write(fileno, write_buf, write_len);
419     if ( rv >= 0 ) {
420       return rv;
421     }
422     if ( rv < 0 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK ) {
423       return rv;
424     }
425   WAIT_WRITE:
426     while (1) {
427       wfds[0].fd = fileno;
428       wfds[0].events = POLLOUT;
429       nfound = poll(wfds, 1, (int)timeout*1000);
430       if ( nfound == 1 ) {
431         break;
432       }
433       if ( nfound == 0 && errno != EINTR ) {
434         return -1;
435       }
436     }
437     goto DO_WRITE;
438 }
439 
440 STATIC_INLINE
441 void
str_s(char * dst,size_t * dst_len,const char * src,int src_len)442 str_s(char * dst, size_t *dst_len, const char * src, int src_len) {
443   int i;
444   int dlen = *dst_len;
445   for ( i=0; i<src_len; i++) {
446     dst[dlen++] = src[i];
447   }
448   *dst_len = dlen;
449 }
450 
451 
452 STATIC_INLINE
453 void
str_i(char * dst,size_t * dst_len,int src,int fig)454 str_i(char * dst, size_t * dst_len, int src, int fig) {
455   int dlen = *dst_len + fig - 1;
456   do {
457     dst[dlen] = '0' + (src % 10);
458     dlen--;
459     src /= 10;
460   } while( dlen >= *dst_len );
461   *dst_len += fig;
462 }
463 
464 
465 STATIC_INLINE
_date_line(char * date_line)466 int _date_line(char * date_line) {
467     struct tm gtm;
468     time_t lt;
469     size_t i = 0;
470     time(&lt);
471     gmtime_r(&lt, &gtm);
472     date_line[i++] = 'D';
473     date_line[i++] = 'a';
474     date_line[i++] = 't';
475     date_line[i++] = 'e';
476     date_line[i++] = ':';
477     date_line[i++] = ' ';
478     str_s(date_line, &i, DoW[gtm.tm_wday], 3);
479     date_line[i++] = ',';
480     date_line[i++] = ' ';
481     str_i(date_line, &i, gtm.tm_mday, 2);
482     date_line[i++] = ' ';
483     str_s(date_line, &i, MoY[gtm.tm_mon], 3);
484     date_line[i++] = ' ';
485     str_i(date_line, &i, gtm.tm_year + 1900, 4);
486     date_line[i++] = ' ';
487     str_i(date_line, &i, gtm.tm_hour,2);
488     date_line[i++] = ':';
489     str_i(date_line, &i, gtm.tm_min,2);
490     date_line[i++] = ':';
491     str_i(date_line, &i, gtm.tm_sec,2);
492     date_line[i++] = ' ';
493     date_line[i++] = 'G';
494     date_line[i++] = 'M';
495     date_line[i++] = 'T';
496     date_line[i++] = 13;
497     date_line[i++] = 10;
498     return i;
499 }
500 
501 STATIC_INLINE
_chunked_header(char * buf,ssize_t len)502 int _chunked_header(char *buf, ssize_t len) {
503     int dlen = 0, i;
504     ssize_t l = len;
505     while ( l > 0 ) {
506         dlen++;
507         l /= 16;
508     }
509     i = dlen;
510     buf[i++] = 13;
511     buf[i++] = 10;
512     buf[i+1] = 0;
513     while ( len > 0 ) {
514         buf[--dlen] = xdigit[len % 16];
515         len /= 16;
516     }
517     return i;
518 }
519 
520 MODULE = Plack::Handler::Gazelle    PACKAGE = Plack::Handler::Gazelle
521 
522 PROTOTYPES: DISABLE
523 
524 BOOT:
525 {
526     AV * psgi_version;
527     psgi_version = newAV();
528     av_extend(psgi_version, 2);
529     (void)av_push(psgi_version,newSViv(1));
530     (void)av_push(psgi_version,newSViv(1));
531     SvREADONLY_on((SV*)psgi_version);
532 
533     HV *e;
534     e = newHV();
535     (void)hv_stores(e,"SCRIPT_NAME",          newSVpvs(""));
536     (void)hv_stores(e,"psgi.version",         newRV((SV*)psgi_version));
537     (void)hv_stores(e,"psgi.errors",          newRV((SV*)PL_stderrgv));
538     (void)hv_stores(e,"psgi.url_scheme",      newSVpvs("http"));
539     (void)hv_stores(e,"psgi.run_once",        newSV(0));
540     (void)hv_stores(e,"psgi.multithread",     newSV(0));
541     (void)hv_stores(e,"psgi.multiprocess",    newSViv(1));
542     (void)hv_stores(e,"psgi.streaming",       newSViv(1));
543     (void)hv_stores(e,"psgi.nonblocking",     newSV(0));
544     (void)hv_stores(e,"psgix.input.buffered", newSViv(1));
545     (void)hv_stores(e,"psgix.harakiri",       newSViv(1));
546 
547     /* stolenn from Feersum */
548     /* placeholders that get defined for every request */
549     (void)hv_stores(e, "SERVER_PROTOCOL", &PL_sv_undef);
550     (void)hv_stores(e, "SERVER_NAME",     &PL_sv_undef);
551     (void)hv_stores(e, "SERVER_PORT",     &PL_sv_undef);
552     (void)hv_stores(e, "REQUEST_URI",     &PL_sv_undef);
553     (void)hv_stores(e, "REQUEST_METHOD",  &PL_sv_undef);
554     (void)hv_stores(e, "PATH_INFO",       &PL_sv_undef);
555     (void)hv_stores(e, "REMOTE_ADDR",     &PL_sv_placeholder);
556     (void)hv_stores(e, "REMOTE_PORT",     &PL_sv_placeholder);
557 
558     /* defaults that get changed for some requests */
559     (void)hv_stores(e, "psgi.input",      &PL_sv_placeholder);
560     (void)hv_stores(e, "CONTENT_LENGTH",  &PL_sv_placeholder);
561     (void)hv_stores(e, "QUERY_STRING",    &PL_sv_placeholder);
562 
563     /* anticipated headers */
564     (void)hv_stores(e, "CONTENT_TYPE",           &PL_sv_placeholder);
565     (void)hv_stores(e, "HTTP_HOST",              &PL_sv_placeholder);
566     (void)hv_stores(e, "HTTP_USER_AGENT",        &PL_sv_placeholder);
567     (void)hv_stores(e, "HTTP_ACCEPT",            &PL_sv_placeholder);
568     (void)hv_stores(e, "HTTP_ACCEPT_LANGUAGE",   &PL_sv_placeholder);
569     (void)hv_stores(e, "HTTP_ACCEPT_CHARSET",    &PL_sv_placeholder);
570     (void)hv_stores(e, "HTTP_REFERER",           &PL_sv_placeholder);
571     (void)hv_stores(e, "HTTP_COOKIE",            &PL_sv_placeholder);
572     (void)hv_stores(e, "HTTP_IF_MODIFIED_SINCE", &PL_sv_placeholder);
573     (void)hv_stores(e, "HTTP_IF_NONE_MATCH",     &PL_sv_placeholder);
574     (void)hv_stores(e, "HTTP_IF_MODIFIED_SINCE", &PL_sv_placeholder);
575     (void)hv_stores(e, "HTTP_IF_NONE_MATCH",     &PL_sv_placeholder);
576     (void)hv_stores(e, "HTTP_CACHE_CONTROL",     &PL_sv_placeholder);
577     (void)hv_stores(e, "HTTP_X_FORWARDED_FOR",   &PL_sv_placeholder);
578 
579     env_template = e;
580 }
581 
582 SV *
583 accept_psgi(fileno, timeout, tcp, host, port)
584     int fileno
585     double timeout
586     int tcp
587     SV * host
588     SV * port
589 PREINIT:
590     int fd;
591     struct sockaddr_in cliaddr;
592     unsigned int len;
593     char read_buf[MAX_HEADER_SIZE];
594     HV * env;
595     int flag = 1;
596     ssize_t rv = 0;
597     ssize_t buf_len;
598     ssize_t reqlen;
599 PPCODE:
600 {
601     /* if ( my ($conn, $buf, $env) = accept_buffer(fileno($server),timeout,tcp,host,port) */
602 
603     len = sizeof(cliaddr);
604     fd = _accept(fileno, (struct sockaddr *)&cliaddr, len);
605     /* endif */
606     if (fd < 0) {
607       goto badexit;
608     }
609 
610     rv = _read_timeout(fd, timeout, &read_buf[0], MAX_HEADER_SIZE);
611     // printf("fd:%d rv:%ld %f %d\n",fd,rv,timeout);
612     if ( rv <= 0 ) {
613       close(fd);
614       goto badexit;
615     }
616 
617     env = newHVhv(env_template);
618 
619     if ( tcp == 1 ) {
620       setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
621       (void)hv_stores(env,"REMOTE_ADDR",newSVpv(inet_ntoa(cliaddr.sin_addr),0));
622       (void)hv_stores(env,"REMOTE_PORT",newSViv(ntohs(cliaddr.sin_port)));
623     }
624     else {
625       (void)hv_stores(env,"REMOTE_ADDR",newSV(0));
626       (void)hv_stores(env,"REMOTE_PORT",newSViv(0));
627     }
628     (void)hv_stores(env,"SERVER_PORT",SvREFCNT_inc(port));
629     (void)hv_stores(env,"SERVER_NAME",SvREFCNT_inc(host));
630 
631     buf_len = rv;
632     while (1) {
633       reqlen = _parse_http_request(aTHX_ &read_buf[0],buf_len,env);
634       if ( reqlen >= 0 ) {
635         break;
636       }
637       else if ( reqlen == -1 ) {
638         /* error */
639         close(fd);
640         goto badexit_clear;
641       }
642       if ( MAX_HEADER_SIZE - buf_len == 0 ) {
643         /* too large header  */
644        char* badreq;
645        badreq = BAD_REQUEST;
646        rv = _write_timeout(fd, timeout, badreq, sizeof(BAD_REQUEST) - 1);
647        close(fd);
648        goto badexit_clear;
649       }
650       /* request is incomplete */
651       rv = _read_timeout(fd, timeout, &read_buf[buf_len], MAX_HEADER_SIZE - buf_len);
652       if ( rv <= 0 ) {
653         close(fd);
654         goto badexit_clear;
655       }
656       buf_len += rv;
657     }
658 
659     /* expect */
660     SV **expect_val = hv_fetch(env, "HTTP_EXPECT" , sizeof("HTTP_EXPECT")-1, 0);
661     if (expect_val != NULL) {
662       if ( strncmp(SvPV_nolen(*expect_val), "100-continue", SvCUR(*expect_val)) == 0 ) {
663         rv = _write_timeout(fd, timeout, EXPECT_CONTINUE, sizeof(EXPECT_CONTINUE) - 1);
664         if ( rv <= 0 ) {
665           close(fd);
666           goto badexit;
667         }
668       } else {
669         rv = _write_timeout(fd, timeout, EXPECT_FAILED, sizeof(EXPECT_FAILED) - 1);
670         close(fd);
671         goto badexit;
672       }
673     }
674 
675     PUSHs(sv_2mortal(newSViv(fd)));
676     PUSHs(sv_2mortal(newSVpvn(&read_buf[reqlen], buf_len - reqlen)));
677     PUSHs(sv_2mortal(newRV_noinc((SV*)env)));
678     XSRETURN(3);
679 
680     badexit_clear:
681     sv_2mortal((SV*)env);
682     badexit:
683     XSRETURN(0);
684 }
685 
686 unsigned long
687 read_timeout(fileno, rbuf, len, offset, timeout)
688     int fileno
689     SV * rbuf
690     ssize_t len
691     ssize_t offset
692     double timeout
693   PREINIT:
694     SV * buf;
695     char * d;
696     ssize_t rv;
697     ssize_t buf_len;
698   CODE:
699     if (!SvROK(rbuf)) croak("ERROR: buf must be RV");
700     buf = SvRV(rbuf);
701     if (!SvOK(buf)) {
702       sv_setpvn(buf,"",0);
703     }
704     SvUPGRADE(buf, SVt_PV);
705     SvPV_nolen(buf);
706     buf_len = SvCUR(buf);
707     if ( len > READ_BUFSZ ) {
708       len = READ_BUFSZ;
709     }
710     d = SvGROW(buf, buf_len + len + 1);
711     rv = _read_timeout(fileno, timeout, &d[offset], len);
712     SvCUR_set(buf, (rv > 0) ? rv + buf_len : buf_len);
713     *SvEND(buf) = '\0';
714     SvPOK_only(buf);
715     if (rv < 0) XSRETURN_UNDEF;
716     RETVAL = (unsigned long)rv;
717   OUTPUT:
718     RETVAL
719 
720 unsigned long
721 write_timeout(fileno, buf, len, offset, timeout)
722     int fileno
723     SV * buf
724     ssize_t len
725     ssize_t offset
726     double timeout
727   PREINIT:
728     char * d;
729     ssize_t rv;
730   CODE:
731     SvUPGRADE(buf, SVt_PV);
732     d = SvPV_nolen(buf);
733     rv = _write_timeout(fileno, timeout, &d[offset], len);
734     if (rv < 0) XSRETURN_UNDEF;
735     RETVAL = (unsigned long)rv;
736   OUTPUT:
737     RETVAL
738 
739 unsigned long
740 write_chunk(fileno, buf, offset, timeout)
741     int fileno
742     SV * buf
743     ssize_t offset
744     double timeout
745   PREINIT:
746     char *d;
747     ssize_t buf_len;
748     ssize_t rv = 0;
749     ssize_t written = 0;
750     ssize_t vec_offset = 0;
751     int count =0;
752     int remain;
753     ssize_t iovcnt = 3;
754     char chunked_header_buf[18];
755   CODE:
756     if ( !SvOK(buf) ) {
757       RETVAL = 0;
758       return;
759     }
760     SvUPGRADE(buf, SVt_PV);
761     d = SvPV_nolen(buf);
762     buf_len = SvCUR(buf);
763     if ( buf_len == 0 ){
764       RETVAL = 0;
765       return;
766     }
767 
768     {
769       struct iovec v[iovcnt]; // Needs C99 compiler
770       v[0].iov_len = _chunked_header(chunked_header_buf,buf_len);
771       v[0].iov_base = chunked_header_buf;
772       v[1].iov_len = buf_len;
773       v[1].iov_base = d;
774       v[2].iov_base = "\r\n";
775       v[2].iov_len = sizeof("\r\n") -1;
776 
777       vec_offset = 0;
778       written = 0;
779       remain = iovcnt;
780       while ( remain > 0 ) {
781         count = (remain > IOV_MAX) ? IOV_MAX : remain;
782         rv = _writev_timeout(fileno, timeout,  &v[vec_offset], count, (vec_offset == 0) ? 0 : 1);
783         if ( rv <= 0 ) {
784           warn("failed to writev: %zd errno:%d", rv, errno);
785           // error or disconnected
786           break;
787         }
788         written += rv;
789         while ( rv > 0 ) {
790           if ( (unsigned int)rv >= v[vec_offset].iov_len ) {
791             rv -= v[vec_offset].iov_len;
792             vec_offset++;
793             remain--;
794           }
795           else {
796             v[vec_offset].iov_base = (char*)v[vec_offset].iov_base + rv;
797             v[vec_offset].iov_len -= rv;
798             rv = 0;
799           }
800         }
801       }
802     }
803 
804     if (rv < 0) XSRETURN_UNDEF;
805     RETVAL = (unsigned long)written;
806   OUTPUT:
807     RETVAL
808 
809 unsigned long
write_all(fileno,buf,offset,timeout)810 write_all(fileno, buf, offset, timeout)
811     int fileno
812     SV * buf
813     ssize_t offset
814     double timeout
815   PREINIT:
816     char * d;
817     ssize_t buf_len;
818     ssize_t rv;
819     ssize_t written = 0;
820   CODE:
821     if ( !SvOK(buf) ) {
822       RETVAL = 0;
823       return;
824     }
825     SvUPGRADE(buf, SVt_PV);
826     d = SvPV_nolen(buf);
827     buf_len = SvCUR(buf);
828     if ( buf_len == 0 ) {
829       RETVAL = 0;
830       return;
831     }
832     written = 0;
833     while ( buf_len > written ) {
834       rv = _write_timeout(fileno, timeout, &d[written], buf_len - written);
835       if ( rv <= 0 ) {
836         break;
837       }
838       written += rv;
839     }
840     if (rv < 0) XSRETURN_UNDEF;
841     RETVAL = (unsigned long)written;
842   OUTPUT:
843     RETVAL
844 
845 
846 void
847 close_client(fileno)
848     int fileno
849   CODE:
850     close(fileno);
851 
852 unsigned long
853 write_informational_response(fileno, timeout, status_code, headers)
854     int fileno
855     double timeout
856     int status_code
857     AV * headers
858   PREINIT:
859     ssize_t rv;
860     ssize_t iovcnt;
861     ssize_t vec_offset;
862     ssize_t written;
863     int count;
864     int remain;
865     size_t i;
866     struct iovec * iv;
867     char status_line[512];
868     char * key;
869     char * val;
870     STRLEN key_len = 0;
871     STRLEN val_len = 0;
872   CODE:
873     if( (av_len(headers)+1) % 2 == 1 ) croak("ERROR: Odd number of element in header");
874     iovcnt = 10 + (av_len(headers)+2)*2;
875     {
876       struct iovec iv[iovcnt]; // Needs C99 compiler
877       /* status line */
878       iovcnt = 0;
879       i=0;
880       status_line[i++] = 'H';
881       status_line[i++] = 'T';
882       status_line[i++] = 'T';
883       status_line[i++] = 'P';
884       status_line[i++] = '/';
885       status_line[i++] = '1';
886       status_line[i++] = '.';
887       status_line[i++] = '1';
888       status_line[i++] = ' ';
889       str_i(status_line,&i,status_code,3);
890       status_line[i++] = ' ';
891       const char * message = status_message(status_code);
892       str_s(status_line,&i, message, strlen(message));
893       status_line[i++] = 13;
894       status_line[i++] = 10;
895       iv[iovcnt].iov_base = status_line;
896       iv[iovcnt].iov_len = i;
897       iovcnt++;
898 
899       i=0;
900       while (i < av_len(headers) + 1 ) {
901         /* key */
902         key = svpv2char(aTHX_ *av_fetch(headers,i,0), &key_len);
903         i++;
904         val = svpv2char(aTHX_ *av_fetch(headers,i,0), &val_len);
905         i++;
906         iv[iovcnt].iov_base = key;
907         iv[iovcnt].iov_len = key_len;
908         iovcnt++;
909         iv[iovcnt].iov_base = ": ";
910         iv[iovcnt].iov_len = sizeof(": ") - 1;
911         iovcnt++;
912         /* value */
913         iv[iovcnt].iov_base = val;
914         iv[iovcnt].iov_len = val_len;
915         iovcnt++;
916         iv[iovcnt].iov_base = "\r\n";
917         iv[iovcnt].iov_len = sizeof("\r\n") - 1;
918         iovcnt++;
919       }
920       iv[iovcnt].iov_base = "\r\n";
921       iv[iovcnt].iov_len = sizeof("\r\n") - 1;
922       iovcnt++;
923 
924       vec_offset = 0;
925       written = 0;
926       remain = iovcnt;
927       while ( remain > 0 ) {
928         count = (remain > IOV_MAX) ? IOV_MAX : remain;
929         rv = _writev_timeout(fileno, timeout,  &iv[vec_offset], count, (vec_offset == 0) ? 0 : 1);
930         if ( rv <= 0 ) {
931           warn("failed to writev: %zd errno:%d", rv, errno);
932           // error or disconnected
933           break;
934         }
935         written += rv;
936         while ( rv > 0 ) {
937           if ( (unsigned int)rv >= iv[vec_offset].iov_len ) {
938             rv -= iv[vec_offset].iov_len;
939             vec_offset++;
940             remain--;
941           }
942           else {
943             iv[vec_offset].iov_base = (char*)iv[vec_offset].iov_base + rv;
944             iv[vec_offset].iov_len -= rv;
945             rv = 0;
946           }
947         }
948       }
949     }
950 
951     if (rv < 0) XSRETURN_UNDEF;
952     RETVAL = (unsigned long) written;
953   OUTPUT:
954     RETVAL
955 
956 
957 unsigned long
958 write_psgi_response(fileno, timeout, status_code, headers, body, use_chunkedv)
959     int fileno
960     double timeout
961     int status_code
962     AV * headers
963     AV * body
964     SV * use_chunkedv
965   ALIAS:
966     Plack::Handler::Gazelle::write_psgi_response = 0
967     Plack::Handler::Gazelle::write_psgi_response_header = 1
968   PREINIT:
969     ssize_t rv;
970     ssize_t iovcnt;
971     ssize_t vec_offset;
972     ssize_t written;
973     int count;
974     int remain;
975     size_t i;
976     struct iovec * v;
977     char status_line[512];
978     char date_line[512];
979     char server_line[1032];
980     char * key;
981     char * val;
982     STRLEN key_len = 0;
983     STRLEN val_len;
984     int date_pushed = 0;
985     const char * s;
986     char* d;
987     ssize_t n;
988     IV use_chunked;
989     char * chunked_header_buf;
990 
991   CODE:
992     if( (av_len(headers)+1) % 2 == 1 ) croak("ERROR: Odd number of element in header");
993     use_chunked = SvIV(use_chunkedv);
994     iovcnt = 10 + (av_len(headers)+2)*2 + (av_len(body) + 1);
995 
996     /* status_with_no_entity_body */
997     if ( status_code < 200 || status_code == 204 || status_code == 304 ) {
998       use_chunked = 0;
999     }
1000 
1001     if ( use_chunked > 0 ) {
1002       iovcnt += (av_len(body)+1)*2;
1003     }
1004     Newx(chunked_header_buf, 18 * (av_len(body)+2), char);
1005 
1006     {
1007       struct iovec v[iovcnt]; // Needs C99 compiler
1008       /* status line */
1009       iovcnt = 0;
1010       i=0;
1011       status_line[i++] = 'H';
1012       status_line[i++] = 'T';
1013       status_line[i++] = 'T';
1014       status_line[i++] = 'P';
1015       status_line[i++] = '/';
1016       status_line[i++] = '1';
1017       status_line[i++] = '.';
1018       status_line[i++] = '1';
1019       status_line[i++] = ' ';
1020       str_i(status_line,&i,status_code,3);
1021       status_line[i++] = ' ';
1022       const char * message = status_message(status_code);
1023       str_s(status_line,&i, message, strlen(message));
1024       status_line[i++] = 13;
1025       status_line[i++] = 10;
1026       v[iovcnt].iov_base = status_line;
1027       v[iovcnt].iov_len = i;
1028       iovcnt++;
1029 
1030       /* for date header */
1031       iovcnt++;
1032 
1033       v[iovcnt].iov_base = "Server: gazelle\r\n";
1034       v[iovcnt].iov_len = sizeof("Server: gazelle\r\n")-1;
1035       iovcnt++;
1036 
1037       i=0;
1038       date_pushed = 0;
1039       while ( i < av_len(headers) + 1 ) {
1040         /* key */
1041         key = svpv2char(aTHX_ *av_fetch(headers,i,0), &key_len);
1042         i++;
1043         if ( strncasecmp(key,"Connection",key_len) == 0 ) {
1044           i++;
1045           continue;
1046         }
1047 
1048         val = svpv2char(aTHX_ *av_fetch(headers,i,0), &val_len);
1049         i++;
1050 
1051         if ( strncasecmp(key,"Date",key_len) == 0 ) {
1052           strcpy(date_line, "Date: ");
1053           for ( s=val, n = val_len, d=date_line+sizeof("Date: ")-1; n !=0; s++, --n, d++) {
1054             *d = *s;
1055           }
1056           date_line[sizeof("Date: ") -1 + val_len] = 13;
1057           date_line[sizeof("Date: ") -1 + val_len + 1] = 10;
1058           v[1].iov_base = date_line;
1059           v[1].iov_len = sizeof("Date: ") -1 + val_len + 2;
1060           date_pushed = 1;
1061           continue;
1062         } else if ( strncasecmp(key,"Server",key_len) == 0 ) {
1063           strcpy(server_line, "Server: ");
1064           for ( s=val, n = val_len, d=server_line+sizeof("Server: ")-1; n !=0; s++, --n, d++) {
1065             *d = *s;
1066           }
1067           server_line[sizeof("Server: ") -1 + val_len] = 13;
1068           server_line[sizeof("Server: ") -1 + val_len + 1] = 10;
1069           v[2].iov_base = server_line;
1070           v[2].iov_len = sizeof("Server: ") -1 + val_len + 2;
1071           continue;
1072         } else if ( strncasecmp(key,"Content-Length",key_len) == 0 || strncasecmp(key,"Transfer-Encoding",key_len) == 0) {
1073             use_chunked = 0;
1074         }
1075 
1076         v[iovcnt].iov_base = key;
1077         v[iovcnt].iov_len = key_len;
1078         iovcnt++;
1079         v[iovcnt].iov_base = ": ";
1080         v[iovcnt].iov_len = sizeof(": ") - 1;
1081         iovcnt++;
1082         /* value */
1083         v[iovcnt].iov_base = val;
1084         v[iovcnt].iov_len = val_len;
1085         iovcnt++;
1086         v[iovcnt].iov_base = "\r\n";
1087         v[iovcnt].iov_len = sizeof("\r\n") - 1;
1088         iovcnt++;
1089       }
1090 
1091       if ( date_pushed == 0 ) {
1092         v[1].iov_len = _date_line(date_line);
1093         v[1].iov_base = date_line;
1094       }
1095 
1096       if ( use_chunked > 0 ) {
1097           v[iovcnt].iov_base = "Transfer-Encoding: chunked\r\n";
1098           v[iovcnt].iov_len = sizeof("Transfer-Encoding: chunked\r\n") - 1;
1099           iovcnt++;
1100       }
1101 
1102       v[iovcnt].iov_base = "Connection: close\r\n\r\n";
1103       v[iovcnt].iov_len = sizeof("Connection: close\r\n\r\n") - 1;
1104       iovcnt++;
1105 
1106       size_t chb_offset = 0;
1107       for (i=0; i < av_len(body) + 1; i++ ) {
1108         SV **b = av_fetch(body,i,0);
1109         if (!SvOK(*b)) {
1110           continue;
1111         }
1112         d = svpv2char(aTHX_ *b, &val_len);
1113         if ( val_len < 1 ) {
1114           continue;
1115         }
1116         if ( use_chunked ) {
1117           v[iovcnt].iov_len = _chunked_header(&chunked_header_buf[chb_offset],val_len);
1118           v[iovcnt].iov_base = &chunked_header_buf[chb_offset];
1119           chb_offset += v[iovcnt].iov_len;
1120           iovcnt++;
1121         }
1122         v[iovcnt].iov_base = d;
1123         v[iovcnt].iov_len = val_len;
1124         iovcnt++;
1125         if ( use_chunked ) {
1126           v[iovcnt].iov_base = "\r\n";
1127           v[iovcnt].iov_len = sizeof("\r\n") -1;
1128           iovcnt++;
1129         }
1130       }
1131 
1132       if ( use_chunked && ix == 0 ) {
1133         v[iovcnt].iov_base = "0\r\n\r\n";
1134         v[iovcnt].iov_len = sizeof("0\r\n\r\n") - 1;
1135         iovcnt++;
1136       }
1137 
1138       vec_offset = 0;
1139       written = 0;
1140       remain = iovcnt;
1141       while ( remain > 0 ) {
1142         count = (remain > IOV_MAX) ? IOV_MAX : remain;
1143         rv = _writev_timeout(fileno, timeout,  &v[vec_offset], count, (vec_offset == 0) ? 0 : 1);
1144         if ( rv <= 0 ) {
1145           warn("failed to writev: %zd errno:%d", rv, errno);
1146           // error or disconnected
1147           break;
1148         }
1149         written += rv;
1150         while ( rv > 0 ) {
1151           if ( (unsigned int)rv >= v[vec_offset].iov_len ) {
1152             rv -= v[vec_offset].iov_len;
1153             vec_offset++;
1154             remain--;
1155           }
1156           else {
1157             v[vec_offset].iov_base = (char*)v[vec_offset].iov_base + rv;
1158             v[vec_offset].iov_len -= rv;
1159             rv = 0;
1160           }
1161         }
1162       }
1163     }
1164     sv_setiv(use_chunkedv, use_chunked);
1165     Safefree(chunked_header_buf);
1166     if (rv < 0) XSRETURN_UNDEF;
1167     RETVAL = (unsigned long) written;
1168   OUTPUT:
1169     RETVAL
1170