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(<);
471 gmtime_r(<, >m);
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