bossan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Hiroki Noda
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2012 @@
1
+ #include "ruby.h"
2
+ #include <assert.h>
3
+ #include <fcntl.h>
4
+ #include <stddef.h>
5
+ #include <unistd.h>
6
+ #include <errno.h>
7
+ #include <stdio.h>
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+ #include <inttypes.h>
11
+ #include <arpa/inet.h>
12
+ #include <signal.h>
13
+ #include <sys/sendfile.h>
14
+ #include <sys/socket.h>
15
+ #include <sys/types.h>
16
+ #include <sys/prctl.h>
17
+ #include <sys/un.h>
18
+ #include <sys/stat.h>
19
+ #include <sys/file.h>
20
+ #include <sys/uio.h>
21
+ #include <netinet/in.h>
22
+ #include <netinet/tcp.h>
23
+ #include <netdb.h>
24
+
25
+ #include "time_cache.h"
26
+ #include "http_parser.h"
27
+ #include "picoev.h"
28
+
29
+ #define MAX_FDS 1024 * 8
30
+ #define ACCEPT_TIMEOUT_SECS 1
31
+ #define SHORT_TIMEOUT_SECS 2
32
+ #define WRITE_TIMEOUT_SECS 5
33
+ #define READ_LONG_TIMEOUT_SECS 5
34
+
35
+ #define BACKLOG 1024
36
+ #define MAX_BUFSIZE 1024 * 8
37
+ #define INPUT_BUF_SIZE 1024 * 8
38
+
39
+ #define LIMIT_MAX 1024 * 1024 * 1024
40
+
41
+ #define LIMIT_SIZE 1024 * 512
42
+
43
+ #define LIMIT_PATH 1024 * 4
44
+ #define LIMIT_FRAGMENT 1024
45
+ #define LIMIT_URI 1024 * 4
46
+ #define LIMIT_QUERY_STRING 1024 * 8
47
+
48
+ #define LIMIT_REQUEST_FIELDS 30
49
+ #define LIMIT_REQUEST_FIELD_SIZE 1024 * 8
50
+
51
+ #define CRLF "\r\n"
52
+ #define DELIM ": "
53
+
54
+ #define MSG_500 ("HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n<html><head><title>500 Internal Server Error</head><h1>Internal Server Error</h1><p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p></html>\n")
55
+
56
+ #define MSG_400 ("HTTP/1.0 400 Bad Request\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n<html><head><title>Bad Request</head><body><p>Bad Request.</p></body></html>")
57
+
58
+ #define MSG_411 ("HTTP/1.0 411 Length Required\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n<html><head><title>Length Required</head><body><p>Length Required.</p></body></html>")
59
+
60
+ #define MSG_413 ("HTTP/1.0 413 Request Entity Too Large\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n<html><head><title>Request Entity Too Large</head><body><p>Request Entity Too Large.</p></body></html>")
61
+
62
+ #define SERVER "bossan/0.1"
63
+
64
+ VALUE server; // Bossan::Server
65
+
66
+ static VALUE version_key;
67
+ static VALUE version_val;
68
+ static VALUE scheme_key;
69
+ static VALUE scheme_val;
70
+ static VALUE errors_key;
71
+ static VALUE errors_val;
72
+ static VALUE multithread_key;
73
+ static VALUE multithread_val;
74
+ static VALUE multiprocess_key;
75
+ static VALUE multiprocess_val;
76
+ static VALUE run_once_key;
77
+ static VALUE run_once_val;
78
+
79
+ static VALUE script_key;
80
+ static VALUE script_val;
81
+ static VALUE server_name_key;
82
+ static VALUE server_name_val;
83
+ static VALUE server_port_key;
84
+ static VALUE server_port_val;
85
+
86
+ static VALUE server_protocol;
87
+ static VALUE path_info;
88
+ static VALUE request_uri;
89
+ static VALUE query_string;
90
+ static VALUE http_fragment;
91
+ static VALUE request_method;
92
+ static VALUE rb_remote_addr;
93
+ static VALUE rb_remote_port;
94
+ static VALUE rack_input;
95
+ static VALUE http_connection;
96
+
97
+ static VALUE http_user_agent;
98
+
99
+ static VALUE i_keys;
100
+ static VALUE i_call;
101
+ static VALUE i_new;
102
+
103
+ static char *server_name = "127.0.0.1";
104
+ static short server_port = 8000;
105
+
106
+ static int listen_sock; // listen socket
107
+
108
+ static int loop_done; // main loop flag
109
+ static picoev_loop* main_loop; //main loop
110
+ static VALUE rack_app = NULL; //rack app
111
+
112
+ static char *log_path = NULL; //access log path
113
+ static int log_fd = -1; //access log
114
+ static char *error_log_path = NULL; //error log path
115
+ static int err_log_fd = -1; //error log
116
+
117
+ static int is_keep_alive = 0; //keep alive support
118
+ int max_content_length = 1024 * 1024 * 16; //max_content_length
119
+
120
+ static VALUE StringIO;
121
+
122
+ typedef enum {
123
+ WRITE_OK,
124
+ MEMORY_ERROR,
125
+ LIMIT_OVER,
126
+ } buffer_result;
127
+
128
+ typedef struct {
129
+ char *buf;
130
+ size_t buf_size;
131
+ size_t len;
132
+ size_t limit;
133
+ } buffer;
134
+
135
+ typedef struct {
136
+ VALUE filelike;
137
+ } FileWrapperObject;
138
+
139
+ typedef enum {
140
+ FIELD,
141
+ VAL,
142
+ } field_type;
143
+
144
+ typedef struct {
145
+ buffer *field;
146
+ buffer *value;
147
+ } header;
148
+
149
+ typedef struct {
150
+ buffer *path;
151
+ buffer *uri;
152
+ buffer *query_string;
153
+ buffer *fragment;
154
+ header *headers[LIMIT_REQUEST_FIELDS];
155
+ uint32_t num_headers;
156
+ field_type last_header_element;
157
+ } request;
158
+
159
+ typedef enum {
160
+ BODY_TYPE_NONE,
161
+ BODY_TYPE_TMPFILE,
162
+ BODY_TYPE_BUFFER
163
+ } request_body_type;
164
+
165
+ typedef struct _client {
166
+ int fd;
167
+ char *remote_addr;
168
+ uint32_t remote_port;
169
+ uint8_t keep_alive;
170
+ request *req;
171
+ uint32_t body_length;
172
+ int body_readed;
173
+ void *body;
174
+ int bad_request_code;
175
+ request_body_type body_type;
176
+ uint8_t complete;
177
+
178
+ http_parser *http; // http req parser
179
+ VALUE environ; // rack environ
180
+ int status_code; // response status code
181
+
182
+ VALUE http_status; // response status line
183
+ VALUE headers; // http response headers
184
+ uint8_t header_done; // header write status
185
+ VALUE response; // rack response object
186
+ VALUE response_iter; // rack response object
187
+ uint8_t content_length_set; // content_length_set flag
188
+ uint32_t content_length; // content_length
189
+ uint32_t write_bytes; // send body length
190
+ void *bucket; //write_data
191
+ uint8_t response_closed; //response closed flag
192
+ } client_t;
193
+
194
+ typedef struct iovec iovec_t;
195
+
196
+ typedef struct {
197
+ int fd;
198
+ iovec_t *iov;
199
+ uint32_t iov_cnt;
200
+ uint32_t iov_size;
201
+ uint32_t total;
202
+ uint32_t total_size;
203
+ } write_bucket;
204
+
205
+ inline buffer *
206
+ new_buffer(size_t buf_size, size_t limit)
207
+ {
208
+ buffer *buf;
209
+ buf = ruby_xmalloc(sizeof(buffer));
210
+ memset(buf, 0, sizeof(buffer));
211
+ buf->buf = ruby_xmalloc(sizeof(char) * buf_size);
212
+ buf->buf_size = buf_size;
213
+ if(limit){
214
+ buf->limit = limit;
215
+ }else{
216
+ buf->limit = LIMIT_MAX;
217
+ }
218
+ return buf;
219
+ }
220
+
221
+ inline buffer_result
222
+ write2buf(buffer *buf, const char *c, size_t l) {
223
+ size_t newl;
224
+ char *newbuf;
225
+ buffer_result ret = WRITE_OK;
226
+ newl = buf->len + l;
227
+
228
+ if (newl >= buf->buf_size) {
229
+ buf->buf_size *= 2;
230
+ if(buf->buf_size <= newl) {
231
+ buf->buf_size = (int)(newl + 1);
232
+ }
233
+ if(buf->buf_size > buf->limit){
234
+ buf->buf_size = buf->limit + 1;
235
+ }
236
+ newbuf = (char*)ruby_xrealloc(buf->buf, buf->buf_size);
237
+ buf->buf = newbuf;
238
+ }
239
+ if(newl >= buf->buf_size){
240
+ l = buf->buf_size - buf->len -1;
241
+ ret = LIMIT_OVER;
242
+ }
243
+ memcpy(buf->buf + buf->len, c , l);
244
+ buf->len += (int)l;
245
+ return ret;
246
+ }
247
+
248
+ inline void
249
+ free_buffer(buffer *buf)
250
+ {
251
+ ruby_xfree(buf->buf);
252
+ ruby_xfree(buf);
253
+ }
254
+
255
+ inline VALUE
256
+ getRbString(buffer *buf)
257
+ {
258
+ VALUE o;
259
+ o = rb_str_new(buf->buf, buf->len);
260
+ free_buffer(buf);
261
+ return o;
262
+ }
263
+
264
+ inline char *
265
+ getString(buffer *buf)
266
+ {
267
+ buf->buf[buf->len] = '\0';
268
+ return buf->buf;
269
+ }
270
+
271
+ int
272
+ open_log_file(const char *path)
273
+ {
274
+ return open(path, O_CREAT|O_APPEND|O_WRONLY, 0744);
275
+ }
276
+
277
+ static inline int
278
+ write_log(const char *new_path, int fd, const char *data, size_t len)
279
+ {
280
+ int openfd;
281
+ flock(fd, LOCK_EX);
282
+
283
+ if(write(fd, data, len) < 0){
284
+ flock(fd, LOCK_UN);
285
+ //reopen
286
+ openfd = open_log_file(new_path);
287
+ if(openfd < 0){
288
+ //fail
289
+ return -1;
290
+ }
291
+ flock(openfd, LOCK_EX);
292
+ if(write(openfd, data, len) < 0){
293
+ flock(openfd, LOCK_UN);
294
+ // write fail
295
+ return -1;
296
+ }
297
+ flock(openfd, LOCK_UN);
298
+ return openfd;
299
+ }
300
+ flock(fd, LOCK_UN);
301
+ return fd;
302
+ }
303
+
304
+ int
305
+ write_access_log(client_t *cli, int log_fd, const char *log_path)
306
+ {
307
+ char buf[1024];
308
+ if(log_fd > 0){
309
+ VALUE obj;
310
+ char *method, *path, *version, *ua;
311
+
312
+ obj = rb_hash_aref(cli->environ, request_method);
313
+ if(obj){
314
+ method = StringValuePtr(obj);
315
+ }else{
316
+ method = "-";
317
+ }
318
+
319
+ obj = rb_hash_aref(cli->environ, path_info);
320
+ if(obj){
321
+ path = StringValuePtr(obj);
322
+ }else{
323
+ path = "-";
324
+ }
325
+
326
+ obj = rb_hash_aref(cli->environ, server_protocol);
327
+ if(obj){
328
+ version = StringValuePtr(obj);
329
+ }else{
330
+ version = "-";
331
+ }
332
+
333
+ obj = rb_hash_aref(cli->environ, http_user_agent);
334
+ if(obj){
335
+ ua = StringValuePtr(obj);
336
+ }else{
337
+ ua = "-";
338
+ }
339
+ //update
340
+ cache_time_update();
341
+
342
+ sprintf(buf, "%s - - [%s] \"%s %s %s\" %d %d \"-\" \"%s\"\n",
343
+ cli->remote_addr,
344
+ http_log_time,
345
+ method,
346
+ path,
347
+ version,
348
+ cli->status_code,
349
+ cli->write_bytes,
350
+ ua);
351
+ return write_log(log_path, log_fd, buf, strlen(buf));
352
+ }
353
+ return 0;
354
+ }
355
+
356
+ static inline int
357
+ blocking_write(client_t *client, char *data, size_t len)
358
+ {
359
+ size_t r = 0, send_len = len;
360
+ while ( (int)len > 0 ){
361
+ if (len < send_len){
362
+ send_len = len;
363
+ }
364
+ r = write(client->fd, data, send_len);
365
+ switch(r){
366
+ case 0:
367
+ return 1;
368
+ break;
369
+ case -1:
370
+ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* try again later */
371
+ //printf("EAGAIN \n");
372
+ usleep(500); //TODO try again later
373
+ break;
374
+ }else{
375
+ // fatal error
376
+ //close
377
+ rb_raise(rb_eException, "fatal error");
378
+
379
+ // TODO:
380
+ // raise exception from errno
381
+ /* rb_raise(rb_eIOError); */
382
+ /* write_error_log(__FILE__, __LINE__); */
383
+ client->keep_alive = 0;
384
+ return -1;
385
+ }
386
+ default:
387
+ data += (int)r;
388
+ len -= r;
389
+ client->content_length += r;
390
+ }
391
+ }
392
+ return 1;
393
+ }
394
+
395
+ void
396
+ send_error_page(client_t *client)
397
+ {
398
+ shutdown(client->fd, SHUT_RD);
399
+ if(client->header_done){
400
+ //already sended response data
401
+ //close connection
402
+ return;
403
+ }
404
+ int status = client->bad_request_code;
405
+ int r = status < 0 ? status * -1 : status;
406
+ client->status_code = r;
407
+ switch(r){
408
+ case 400:
409
+ blocking_write(client, MSG_400, sizeof(MSG_400) -1);
410
+ break;
411
+ case 411:
412
+ blocking_write(client, MSG_411, sizeof(MSG_411) -1);
413
+ break;
414
+ case 413:
415
+ blocking_write(client, MSG_413, sizeof(MSG_413) -1);
416
+ break;
417
+ default:
418
+ //Internal Server Error
419
+ blocking_write(client, MSG_500, sizeof(MSG_500) -1);
420
+ break;
421
+ }
422
+ client->keep_alive = 0;
423
+ }
424
+
425
+ static inline void
426
+ extent_sndbuf(client_t *client)
427
+ {
428
+ int bufsize = 1024 * 1024 * 2, r;
429
+ r = setsockopt(client->fd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
430
+ assert(r == 0);
431
+ }
432
+
433
+ static inline void
434
+ enable_cork(client_t *client)
435
+ {
436
+ int on = 1, r;
437
+ r = setsockopt(client->fd, IPPROTO_TCP, TCP_CORK, &on, sizeof(on));
438
+ assert(r == 0);
439
+ }
440
+
441
+ static inline write_bucket *
442
+ new_write_bucket(int fd, int cnt)
443
+ {
444
+ write_bucket *bucket;
445
+ bucket = ruby_xmalloc(sizeof(write_bucket));
446
+ memset(bucket, 0, sizeof(write_bucket));
447
+
448
+ bucket->fd = fd;
449
+ bucket->iov = (iovec_t *)ruby_xmalloc(sizeof(iovec_t) * cnt);
450
+ bucket->iov_size = cnt;
451
+ return bucket;
452
+ }
453
+
454
+ static inline void
455
+ free_write_bucket(write_bucket *bucket)
456
+ {
457
+ ruby_xfree(bucket->iov);
458
+ ruby_xfree(bucket);
459
+ }
460
+
461
+ static inline void
462
+ set2bucket(write_bucket *bucket, char *buf, size_t len)
463
+ {
464
+ bucket->iov[bucket->iov_cnt].iov_base = buf;
465
+ bucket->iov[bucket->iov_cnt].iov_len = len;
466
+ bucket->iov_cnt++;
467
+ bucket->total += len;
468
+ bucket->total_size += len;
469
+ }
470
+
471
+ static inline void
472
+ add_header(write_bucket *bucket, char *key, size_t keylen, char *val, size_t vallen)
473
+ {
474
+ set2bucket(bucket, key, keylen);
475
+ set2bucket(bucket, DELIM, 2);
476
+ set2bucket(bucket, val, vallen);
477
+ set2bucket(bucket, CRLF, 2);
478
+ }
479
+
480
+ static inline int
481
+ writev_bucket(write_bucket *data)
482
+ {
483
+ size_t w;
484
+ int i = 0;
485
+ w = writev(data->fd, data->iov, data->iov_cnt);
486
+ if(w == -1){
487
+ //error
488
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
489
+ // try again later
490
+ return 0;
491
+ }else{
492
+ //ERROR
493
+ rb_raise(rb_eException, "fatal error");
494
+
495
+ // TODO:
496
+ // raise exception from errno
497
+ /* rb_raise(rb_eIOError); */
498
+ /* write_error_log(__FILE__, __LINE__); */
499
+ return -1;
500
+ }
501
+ }if(w == 0){
502
+ return 1;
503
+ }else{
504
+ if(data->total > w){
505
+ for(; i < data->iov_cnt;i++){
506
+ if(w > data->iov[i].iov_len){
507
+ //already write
508
+ w -= data->iov[i].iov_len;
509
+ data->iov[i].iov_len = 0;
510
+ }else{
511
+ data->iov[i].iov_base += w;
512
+ data->iov[i].iov_len = data->iov[i].iov_len - w;
513
+ break;
514
+ }
515
+ }
516
+ data->total = data->total -w;
517
+ #ifdef DEBUG
518
+ printf("writev_bucket write %d progeress %d/%d \n", w, data->total, data->total_size);
519
+ #endif
520
+ //resume
521
+ // again later
522
+ return writev_bucket(data);
523
+ }
524
+ }
525
+ return 1;
526
+ }
527
+
528
+ static inline int
529
+ write_headers(client_t *client, char *data, size_t datalen)
530
+ {
531
+ if(client->header_done){
532
+ return 1;
533
+ }
534
+ write_bucket *bucket;
535
+ uint32_t i = 0, hlen = 0;
536
+
537
+ VALUE arr = NULL;
538
+ VALUE object = NULL;
539
+ char *name = NULL;
540
+ ssize_t namelen;
541
+ char *value = NULL;
542
+ long valuelen;
543
+
544
+ if(client->headers){
545
+ if (TYPE(client->headers) != T_HASH) {
546
+ return -1;
547
+ }
548
+ arr = rb_funcall(client->headers, i_keys, 0);
549
+ hlen = RARRAY_LEN(arr);
550
+ }
551
+ bucket = new_write_bucket(client->fd, ( hlen * 4 * 2) + 32 );
552
+
553
+ object = client->http_status;
554
+
555
+ if(TYPE(object) != T_STRING){
556
+ return -1;
557
+ }
558
+
559
+ if(object){
560
+ value = StringValuePtr(object);
561
+ valuelen = RSTRING_LEN(object);
562
+ //write status code
563
+ set2bucket(bucket, value, valuelen);
564
+
565
+ add_header(bucket, "Server", 6, SERVER, sizeof(SERVER) -1);
566
+ cache_time_update();
567
+ add_header(bucket, "Date", 4, (char *)http_time, 29);
568
+ if(client->keep_alive == 1){
569
+ add_header(bucket, "Connection", 10, "keep-alive", 10);
570
+ }
571
+ }
572
+
573
+ VALUE object1, object2;
574
+
575
+ //write header
576
+ if(client->headers){
577
+ for(i=0; i < hlen; i++){
578
+ object1 = rb_ary_entry(arr, i);
579
+ Check_Type(object1, T_STRING);
580
+
581
+ if (TYPE(client->headers)!=T_HASH){
582
+ goto error;
583
+ }
584
+ VALUE tmp = rb_funcall(client->headers, rb_intern("key?"), 1, object1);
585
+ if (tmp == Qfalse){
586
+ goto error;
587
+ }
588
+ object2 = rb_hash_aref(client->headers, object1);
589
+
590
+ Check_Type(object2, T_STRING);
591
+
592
+ name = StringValuePtr(object1);
593
+ namelen = RSTRING_LEN(object1);
594
+
595
+ value = StringValuePtr(object2);
596
+ valuelen = RSTRING_LEN(object2);
597
+
598
+ if (strchr(name, '\n') != 0 || strchr(value, '\n') != 0) {
599
+ rb_raise(rb_eArgError, "embedded newline in response header and value");
600
+ }
601
+
602
+ if (!strcasecmp(name, "Server") || !strcasecmp(name, "Date")) {
603
+ continue;
604
+ }
605
+
606
+ if (!strcasecmp(name, "Content-Length")) {
607
+ char *v = value;
608
+ long l = 0;
609
+
610
+ errno = 0;
611
+ l = strtol(v, &v, 10);
612
+ if (*v || errno == ERANGE || l < 0) {
613
+ rb_raise(rb_eArgError, "invalid content length");
614
+ goto error;
615
+ }
616
+ client->content_length_set = 1;
617
+ client->content_length = l;
618
+ }
619
+ add_header(bucket, name, namelen, value, valuelen);
620
+ }
621
+ }
622
+ set2bucket(bucket, CRLF, 2);
623
+
624
+ if(data){
625
+ set2bucket(bucket, data, datalen);
626
+ }
627
+ client->bucket = bucket;
628
+ int ret = writev_bucket(bucket);
629
+ if(ret != 0){
630
+ client->header_done = 1;
631
+ if(ret > 0 && data){
632
+ client->write_bytes += datalen;
633
+ }
634
+ // clear
635
+ free_write_bucket(bucket);
636
+ client->bucket = NULL;
637
+ }
638
+ return ret;
639
+ error:
640
+ /* write_error_log(__FILE__, __LINE__); */
641
+ if(bucket){
642
+ free_write_bucket(bucket);
643
+ client->bucket = NULL;
644
+ }
645
+ return -1;
646
+ }
647
+
648
+ /* static inline int */
649
+ /* write_sendfile(int out_fd, int in_fd, size_t count) */
650
+ /* { */
651
+ /* int size = (int)count; */
652
+
653
+ /* if (size == 0) { */
654
+ /* struct stat info; */
655
+ /* if (fstat(in_fd, &info) == -1){ */
656
+ /* // TODO: */
657
+ /* // raise exception from errno */
658
+ /* /\* rb_raise(); *\/ */
659
+ /* /\* write_error_log(__FILE__, __LINE__); *\/ */
660
+ /* return -1; */
661
+ /* } */
662
+ /* size = info.st_size - lseek(in_fd, 0, SEEK_CUR); */
663
+ /* } */
664
+ /* return sendfile(out_fd, in_fd, NULL, count); */
665
+ /* } */
666
+
667
+ static inline void
668
+ close_response(client_t *client)
669
+ {
670
+ //send all response
671
+ //closing reponse object
672
+ client->response_closed = 1;
673
+ }
674
+
675
+ static inline int
676
+ processs_write(client_t *client)
677
+ {
678
+ VALUE iterator = NULL;
679
+ VALUE arr;
680
+ VALUE item;
681
+ char *buf;
682
+ ssize_t buflen;
683
+ write_bucket *bucket;
684
+ int ret;
685
+
686
+ // body
687
+ iterator = client->response_iter;
688
+
689
+ if(iterator != NULL){
690
+ /* Check_Type(iterator, T_ARRAY); */
691
+ /* assert(3 == RARRAY_LEN(iterator)); */
692
+ if (TYPE(iterator) != T_ARRAY || RARRAY_LEN(iterator) != 3){
693
+ return -1;
694
+ }
695
+
696
+ arr = rb_ary_entry(iterator, 2);
697
+
698
+ if (TYPE(arr) != T_ARRAY){
699
+ return -1;
700
+ }
701
+
702
+ item = rb_ary_entry(arr, 0);
703
+
704
+ if(TYPE(item) != T_STRING) {
705
+ return -1;
706
+ }
707
+
708
+ buf = StringValuePtr(item);
709
+ buflen = RSTRING_LEN(item);
710
+ //write
711
+ bucket = new_write_bucket(client->fd, 1);
712
+ set2bucket(bucket, buf, buflen);
713
+ ret = writev_bucket(bucket);
714
+ if(ret <= 0){
715
+ return ret;
716
+ }
717
+ //mark
718
+ client->write_bytes += buflen;
719
+ //check write_bytes/content_length
720
+ if(client->content_length_set){
721
+ if(client->content_length <= client->write_bytes){
722
+ // all done
723
+ //break;
724
+ }
725
+ }
726
+ close_response(client);
727
+ }
728
+ return 1;
729
+ }
730
+
731
+ inline int
732
+ process_body(client_t *client)
733
+ {
734
+ int ret;
735
+ write_bucket *bucket;
736
+ if(client->bucket){
737
+ bucket = (write_bucket *)client->bucket;
738
+ //retry send
739
+ ret = writev_bucket(bucket);
740
+
741
+ if(ret != 0){
742
+ client->write_bytes += bucket->total_size;
743
+ //free
744
+ free_write_bucket(bucket);
745
+ client->bucket = NULL;
746
+ }else{
747
+ return 0;
748
+ }
749
+ }
750
+ ret = processs_write(client);
751
+ return ret;
752
+ }
753
+
754
+ static inline int
755
+ start_response_write(client_t *client)
756
+ {
757
+ VALUE iterator;
758
+ VALUE arr;
759
+ VALUE item;
760
+ char *buf;
761
+ ssize_t buflen;
762
+
763
+ iterator = client->response;
764
+ client->response_iter = iterator;
765
+
766
+ if (TYPE(iterator) != T_ARRAY){
767
+ return -1;
768
+ }
769
+ assert(3 == RARRAY_LEN(iterator));
770
+
771
+ arr = rb_ary_entry(iterator, 2);
772
+
773
+ if (TYPE(arr) != T_ARRAY){
774
+ return -1;
775
+ }
776
+
777
+ VALUE v_body = rb_ary_entry(arr, 0);
778
+ Check_Type(v_body, T_STRING);
779
+
780
+ if (v_body) {
781
+ buf = StringValuePtr(v_body);
782
+ buflen = RSTRING_LEN(v_body);
783
+ #ifdef DEBUG
784
+ printf("start_response_write buflen %d \n", buflen);
785
+ #endif
786
+ return write_headers(client, buf, buflen);
787
+ }
788
+ return -1;
789
+ }
790
+
791
+ inline int
792
+ response_start(client_t *client)
793
+ {
794
+ int ret;
795
+ enable_cork(client);
796
+ if(client->status_code == 304){
797
+ return write_headers(client, NULL, 0);
798
+ }
799
+ ret = start_response_write(client);
800
+ #ifdef DEBUG
801
+ printf("start_response_write ret = %d \n", ret);
802
+ #endif
803
+ if(ret > 0){
804
+ // sended header
805
+ ret = processs_write(client);
806
+ }
807
+ return ret;
808
+ }
809
+
810
+ inline request *
811
+ new_request(void)
812
+ {
813
+ request *req = (request *)ruby_xmalloc(sizeof(request));
814
+ memset(req, 0, sizeof(request));
815
+ return req;
816
+ }
817
+
818
+ inline header *
819
+ new_header(size_t fsize, size_t flimit, size_t vsize, size_t vlimit)
820
+ {
821
+ header *h;
822
+ h = ruby_xmalloc(sizeof(header));
823
+ h->field = new_buffer(fsize, flimit);
824
+ h->value = new_buffer(vsize, vlimit);
825
+ return h;
826
+ }
827
+
828
+ inline void
829
+ free_header(header *h)
830
+ {
831
+ ruby_xfree(h);
832
+ }
833
+
834
+ inline void
835
+ free_request(request *req)
836
+ {
837
+ uint32_t i;
838
+ header *h;
839
+ if(req->path){
840
+ free_buffer(req->path);
841
+ req->path = NULL;
842
+ }
843
+ if(req->uri){
844
+ free_buffer(req->uri);
845
+ req->uri = NULL;
846
+ }
847
+ if(req->query_string){
848
+ free_buffer(req->query_string);
849
+ req->query_string = NULL;
850
+ }
851
+ if(req->fragment){
852
+ free_buffer(req->fragment);
853
+ req->fragment = NULL;
854
+ }
855
+ for(i = 0; i < req->num_headers+1; i++){
856
+ h = req->headers[i];
857
+ if(h){
858
+ free_buffer(h->field);
859
+ free_buffer(h->value);
860
+ free_header(h);
861
+ req->headers[i] = NULL;
862
+ }
863
+ }
864
+ ruby_xfree(req);
865
+ }
866
+
867
+ static inline void
868
+ key_upper(char *s, const char *key, size_t len)
869
+ {
870
+ int i = 0;
871
+ register int c;
872
+ for (i = 0; i < len; i++) {
873
+ c = key[i];
874
+ if(c == '-'){
875
+ s[i] = '_';
876
+ }else{
877
+ if(islower(c)){
878
+ s[i] = toupper(c);
879
+ }else{
880
+ s[i] = c;
881
+ }
882
+ }
883
+ }
884
+ }
885
+
886
+ static inline int
887
+ write_body2file(client_t *client, const char *buffer, size_t buffer_len)
888
+ {
889
+ FILE *tmp = (FILE *)client->body;
890
+ fwrite(buffer, 1, buffer_len, tmp);
891
+ client->body_readed += buffer_len;
892
+ #ifdef DEBUG
893
+ printf("write_body2file %d bytes \n", buffer_len);
894
+ #endif
895
+ return client->body_readed;
896
+ }
897
+
898
+ static inline int
899
+ write_body2mem(client_t *client, const char *buffer, size_t buffer_len)
900
+ {
901
+ printf("body2mem called\n");
902
+ VALUE obj = (VALUE)client->body;
903
+ rb_str_concat(obj, rb_str_new(buffer, buffer_len));
904
+ client->body_readed += buffer_len;
905
+ #ifdef DEBUG
906
+ printf("write_body2mem %d bytes \n", buffer_len);
907
+ #endif
908
+ return client->body_readed;
909
+ }
910
+
911
+ static inline int
912
+ write_body(client_t *cli, const char *buffer, size_t buffer_len)
913
+ {
914
+ return write_body2mem(cli, buffer, buffer_len);
915
+ }
916
+
917
+ typedef enum{
918
+ CONTENT_TYPE,
919
+ CONTENT_LENGTH,
920
+ OTHER
921
+ } rack_header_type;
922
+
923
+ static inline rack_header_type
924
+ check_header_type(const char *buf)
925
+ {
926
+ if(*buf++ != 'C'){
927
+ return OTHER;
928
+ }
929
+ if(*buf++ != 'O'){
930
+ return OTHER;
931
+ }
932
+ if(*buf++ != 'N'){
933
+ return OTHER;
934
+ }
935
+ if(*buf++ != 'T'){
936
+ return OTHER;
937
+ }
938
+ if(*buf++ != 'E'){
939
+ return OTHER;
940
+ }
941
+ if(*buf++ != 'N'){
942
+ return OTHER;
943
+ }
944
+ if(*buf++ != 'T'){
945
+ return OTHER;
946
+ }
947
+ if(*buf++ != '_'){
948
+ return OTHER;
949
+ }
950
+ char c = *buf++;
951
+ if(c == 'L'){
952
+ return CONTENT_LENGTH;
953
+ }else if(c == 'T'){
954
+ return CONTENT_TYPE;
955
+ }
956
+ return OTHER;
957
+ }
958
+
959
+ static inline client_t *
960
+ get_client(http_parser *p)
961
+ {
962
+ return (client_t *)p->data;
963
+ }
964
+
965
+ int
966
+ message_begin_cb(http_parser *p)
967
+ {
968
+ return 0;
969
+ }
970
+
971
+ int
972
+ header_field_cb (http_parser *p, const char *buf, size_t len, char partial)
973
+ {
974
+ uint32_t i;
975
+ register header *h;
976
+ client_t *client = get_client(p);
977
+ register request *req = client->req;
978
+ char temp[len];
979
+
980
+ buffer_result ret = MEMORY_ERROR;
981
+ if (req->last_header_element != FIELD){
982
+ if(LIMIT_REQUEST_FIELDS <= req->num_headers){
983
+ client->bad_request_code = 400;
984
+ return -1;
985
+ }
986
+ req->num_headers++;
987
+ }
988
+ i = req->num_headers;
989
+ h = req->headers[i];
990
+
991
+ key_upper(temp, buf, len);
992
+ if(h){
993
+ ret = write2buf(h->field, temp, len);
994
+ }else{
995
+ req->headers[i] = h = new_header(128, LIMIT_REQUEST_FIELD_SIZE, 1024, LIMIT_REQUEST_FIELD_SIZE);
996
+ rack_header_type type = check_header_type(temp);
997
+ if(type == OTHER){
998
+ ret = write2buf(h->field, "HTTP_", 5);
999
+ }
1000
+ ret = write2buf(h->field, temp, len);
1001
+ //printf("%s \n", getString(h->field));
1002
+ }
1003
+ switch(ret){
1004
+ case MEMORY_ERROR:
1005
+ client->bad_request_code = 500;
1006
+ return -1;
1007
+ case LIMIT_OVER:
1008
+ client->bad_request_code = 400;
1009
+ return -1;
1010
+ default:
1011
+ break;
1012
+ }
1013
+ req->last_header_element = FIELD;
1014
+ return 0;
1015
+ }
1016
+
1017
+ int
1018
+ header_value_cb (http_parser *p, const char *buf, size_t len, char partial)
1019
+ {
1020
+ uint32_t i;
1021
+ register header *h;
1022
+ client_t *client = get_client(p);
1023
+ register request *req = client->req;
1024
+
1025
+ buffer_result ret = MEMORY_ERROR;
1026
+ i = req->num_headers;
1027
+ h = req->headers[i];
1028
+
1029
+ if(h){
1030
+ ret = write2buf(h->value, buf, len);
1031
+ }
1032
+ switch(ret){
1033
+ case MEMORY_ERROR:
1034
+ client->bad_request_code = 500;
1035
+ return -1;
1036
+ case LIMIT_OVER:
1037
+ client->bad_request_code = 400;
1038
+ return -1;
1039
+ default:
1040
+ break;
1041
+ }
1042
+ req->last_header_element = VAL;
1043
+ return 0;
1044
+ }
1045
+
1046
+ int
1047
+ request_path_cb (http_parser *p, const char *buf, size_t len, char partial)
1048
+ {
1049
+ client_t *client = get_client(p);
1050
+ register request *req = client->req;
1051
+ buffer_result ret = MEMORY_ERROR;
1052
+
1053
+ if(req->path){
1054
+ ret = write2buf(req->path, buf, len);
1055
+ }else{
1056
+ req->path = new_buffer(1024, LIMIT_PATH);
1057
+ ret = write2buf(req->path, buf, len);
1058
+ }
1059
+ switch(ret){
1060
+ case MEMORY_ERROR:
1061
+ client->bad_request_code = 500;
1062
+ return -1;
1063
+ case LIMIT_OVER:
1064
+ client->bad_request_code = 400;
1065
+ return -1;
1066
+ default:
1067
+ break;
1068
+ }
1069
+ return 0;
1070
+ }
1071
+
1072
+ int
1073
+ request_uri_cb (http_parser *p, const char *buf, size_t len, char partial)
1074
+ {
1075
+ client_t *client = get_client(p);
1076
+ register request *req = client->req;
1077
+ buffer_result ret = MEMORY_ERROR;
1078
+
1079
+ if(req->uri){
1080
+ ret = write2buf(req->uri, buf, len);
1081
+ }else{
1082
+ req->uri = new_buffer(1024, LIMIT_URI);
1083
+ ret = write2buf(req->uri, buf, len);
1084
+ }
1085
+ switch(ret){
1086
+ case MEMORY_ERROR:
1087
+ client->bad_request_code = 500;
1088
+ return -1;
1089
+ case LIMIT_OVER:
1090
+ client->bad_request_code = 400;
1091
+ return -1;
1092
+ default:
1093
+ break;
1094
+ }
1095
+ return 0;
1096
+ }
1097
+
1098
+ int
1099
+ query_string_cb (http_parser *p, const char *buf, size_t len, char partial)
1100
+ {
1101
+ client_t *client = get_client(p);
1102
+ register request *req = client->req;
1103
+ buffer_result ret = MEMORY_ERROR;
1104
+
1105
+ if(req->query_string){
1106
+ ret = write2buf(req->query_string, buf, len);
1107
+ }else{
1108
+ req->query_string = new_buffer(1024*2, LIMIT_QUERY_STRING);
1109
+ ret = write2buf(req->query_string, buf, len);
1110
+ }
1111
+ switch(ret){
1112
+ case MEMORY_ERROR:
1113
+ client->bad_request_code = 500;
1114
+ return -1;
1115
+ case LIMIT_OVER:
1116
+ client->bad_request_code = 400;
1117
+ return -1;
1118
+ default:
1119
+ break;
1120
+ }
1121
+ return 0;
1122
+ }
1123
+
1124
+ int
1125
+ fragment_cb (http_parser *p, const char *buf, size_t len, char partial)
1126
+ {
1127
+ client_t *client = get_client(p);
1128
+ register request *req = client->req;
1129
+ buffer_result ret = MEMORY_ERROR;
1130
+
1131
+ if(req->fragment){
1132
+ ret = write2buf(req->fragment, buf, len);
1133
+ }else{
1134
+ req->fragment = new_buffer(1024, LIMIT_FRAGMENT);
1135
+ ret = write2buf(req->fragment, buf, len);
1136
+ }
1137
+ switch(ret){
1138
+ case MEMORY_ERROR:
1139
+ client->bad_request_code = 500;
1140
+ return -1;
1141
+ case LIMIT_OVER:
1142
+ client->bad_request_code = 400;
1143
+ return -1;
1144
+ default:
1145
+ break;
1146
+ }
1147
+ return 0;
1148
+ }
1149
+
1150
+ int
1151
+ body_cb (http_parser *p, const char *buf, size_t len, char partial)
1152
+ {
1153
+ client_t *client = get_client(p);
1154
+ if(max_content_length <= client->body_readed + len){
1155
+ client->bad_request_code = 413;
1156
+ return -1;
1157
+ }
1158
+ if(client->body_type == BODY_TYPE_NONE){
1159
+ if(client->body_length == 0){
1160
+ //Length Required
1161
+ client->bad_request_code = 411;
1162
+ return -1;
1163
+ }
1164
+ //default memory stream
1165
+ #ifdef DEBUG
1166
+ printf("client->body_length %d \n", client->body_length);
1167
+ #endif
1168
+ client->body_type = BODY_TYPE_BUFFER;
1169
+ #ifdef DEBUG
1170
+ printf("BODY_TYPE_BUFFER \n");
1171
+ #endif
1172
+ }
1173
+ write_body(client, buf, len);
1174
+ return 0;
1175
+ }
1176
+
1177
+ int
1178
+ headers_complete_cb(http_parser *p)
1179
+ {
1180
+ register VALUE obj, key;
1181
+ client_t *client = get_client(p);
1182
+ request *req = client->req;
1183
+ register VALUE env = client->environ;
1184
+ register uint32_t i = 0;
1185
+ register header *h;
1186
+
1187
+ if(max_content_length < p->content_length){
1188
+ client->bad_request_code = 413;
1189
+ return -1;
1190
+ }
1191
+
1192
+ if (p->http_minor == 1) {
1193
+ obj = rb_str_new2("HTTP/1.1");
1194
+ } else {
1195
+ obj = rb_str_new2("HTTP/1.0");
1196
+ }
1197
+ rb_hash_aset(env, server_protocol, obj);
1198
+
1199
+ if(req->path){
1200
+ obj = getRbString(req->path);
1201
+ rb_hash_aset(env, path_info, obj);
1202
+ req->path = NULL;
1203
+ }
1204
+ if(req->uri){
1205
+ obj = getRbString(req->uri);
1206
+ rb_hash_aset(env, request_uri, obj);
1207
+ req->uri = NULL;
1208
+ }
1209
+ if(req->query_string){
1210
+ obj = getRbString(req->query_string);
1211
+ rb_hash_aset(env, query_string, obj);
1212
+ req->query_string = NULL;
1213
+ }
1214
+ if(req->fragment){
1215
+ obj = getRbString(req->fragment);
1216
+ rb_hash_aset(env, http_fragment, obj);
1217
+ req->fragment = NULL;
1218
+ }
1219
+ for(i = 0; i < req->num_headers+1; i++){
1220
+ h = req->headers[i];
1221
+ if(h){
1222
+ key = getRbString(h->field);
1223
+ obj = getRbString(h->value);
1224
+ rb_hash_aset(env, key, obj);
1225
+ free_header(h);
1226
+ req->headers[i] = NULL;
1227
+ }
1228
+ }
1229
+
1230
+ switch(p->method){
1231
+ case HTTP_DELETE:
1232
+ obj = rb_str_new("DELETE", 6);
1233
+ break;
1234
+ case HTTP_GET:
1235
+ obj = rb_str_new("GET", 3);
1236
+ break;
1237
+ case HTTP_HEAD:
1238
+ obj = rb_str_new("HEAD", 4);
1239
+ break;
1240
+ case HTTP_POST:
1241
+ obj = rb_str_new("POST", 4);
1242
+ break;
1243
+ case HTTP_PUT:
1244
+ obj = rb_str_new("PUT", 3);
1245
+ break;
1246
+ case HTTP_CONNECT:
1247
+ obj = rb_str_new("CONNECT", 7);
1248
+ break;
1249
+ case HTTP_OPTIONS:
1250
+ obj = rb_str_new("OPTIONS", 7);
1251
+ break;
1252
+ case HTTP_TRACE:
1253
+ obj = rb_str_new("TRACE", 5);
1254
+ break;
1255
+ case HTTP_COPY:
1256
+ obj = rb_str_new("COPY", 4);
1257
+ break;
1258
+ case HTTP_LOCK:
1259
+ obj = rb_str_new("LOCK", 4);
1260
+ break;
1261
+ case HTTP_MKCOL:
1262
+ obj = rb_str_new("MKCOL", 5);
1263
+ break;
1264
+ case HTTP_MOVE:
1265
+ obj = rb_str_new("MOVE", 4);
1266
+ break;
1267
+ case HTTP_PROPFIND:
1268
+ obj = rb_str_new("PROPFIND", 8);
1269
+ break;
1270
+ case HTTP_PROPPATCH:
1271
+ obj = rb_str_new("PROPPATCH", 9);
1272
+ break;
1273
+ case HTTP_UNLOCK:
1274
+ obj = rb_str_new("UNLOCK", 6);
1275
+ break;
1276
+ case HTTP_REPORT:
1277
+ obj = rb_str_new("REPORT", 6);
1278
+ break;
1279
+ case HTTP_MKACTIVITY:
1280
+ obj = rb_str_new("MKACTIVITY", 10);
1281
+ break;
1282
+ case HTTP_CHECKOUT:
1283
+ obj = rb_str_new("CHECKOUT", 8);
1284
+ break;
1285
+ case HTTP_MERGE:
1286
+ obj = rb_str_new("MERGE", 5);
1287
+ break;
1288
+ default:
1289
+ obj = rb_str_new("GET", 3);
1290
+ break;
1291
+ }
1292
+
1293
+ rb_hash_aset(env, request_method, obj);
1294
+
1295
+ ruby_xfree(req);
1296
+ client->req = NULL;
1297
+ client->body_length = p->content_length;
1298
+ return 0;
1299
+ }
1300
+
1301
+ int
1302
+ message_complete_cb (http_parser *p)
1303
+ {
1304
+ client_t *client = get_client(p);
1305
+ client->complete = 1;
1306
+ return 0;
1307
+ }
1308
+
1309
+ static http_parser_settings settings =
1310
+ {.on_message_begin = message_begin_cb
1311
+ ,.on_header_field = header_field_cb
1312
+ ,.on_header_value = header_value_cb
1313
+ ,.on_path = request_path_cb
1314
+ ,.on_url = request_uri_cb
1315
+ ,.on_fragment = fragment_cb
1316
+ ,.on_query_string = query_string_cb
1317
+ ,.on_body = body_cb
1318
+ ,.on_headers_complete = headers_complete_cb
1319
+ ,.on_message_complete = message_complete_cb
1320
+ };
1321
+
1322
+ inline int
1323
+ init_parser(client_t *cli, const char *name, const short port)
1324
+ {
1325
+ register VALUE object;
1326
+
1327
+ cli->http = (http_parser*)ruby_xmalloc(sizeof(http_parser));
1328
+ memset(cli->http, 0, sizeof(http_parser));
1329
+
1330
+ cli->environ = rb_hash_new();
1331
+
1332
+ if (cli->environ == NULL) {
1333
+ return -1;
1334
+ }
1335
+
1336
+ rb_hash_aset(cli->environ, version_key, version_val);
1337
+ rb_hash_aset(cli->environ, scheme_key, scheme_val);
1338
+ rb_hash_aset(cli->environ, errors_key, errors_val);
1339
+ rb_hash_aset(cli->environ, multithread_key, multithread_val);
1340
+ rb_hash_aset(cli->environ, multiprocess_key, multiprocess_val);
1341
+ rb_hash_aset(cli->environ, run_once_key, run_once_val);
1342
+ rb_hash_aset(cli->environ, script_key, script_val);
1343
+ rb_hash_aset(cli->environ, server_name_key, server_name_val);
1344
+ rb_hash_aset(cli->environ, server_port_key, server_port_val);
1345
+
1346
+ object = rb_str_new2(cli->remote_addr);
1347
+ rb_hash_aset(cli->environ, rb_remote_addr, object);
1348
+
1349
+ object = INT2NUM(cli->remote_port);
1350
+ rb_hash_aset(cli->environ, rb_remote_port, object);
1351
+
1352
+ http_parser_init(cli->http, HTTP_REQUEST);
1353
+ cli->http->data = cli;
1354
+
1355
+ return 0;
1356
+ }
1357
+
1358
+ inline size_t
1359
+ execute_parse(client_t *cli, const char *data, size_t len)
1360
+ {
1361
+ return http_parser_execute(cli->http, &settings, data, len);
1362
+ }
1363
+
1364
+ inline int
1365
+ parser_finish(client_t *cli)
1366
+ {
1367
+ return cli->complete;
1368
+ }
1369
+
1370
+ inline void
1371
+ setup_static_env(char *name, int port)
1372
+ {
1373
+ version_val = rb_obj_freeze(rb_ary_new3(2, INT2FIX(1), INT2FIX(1)));
1374
+ version_key = rb_str_new2("rack.version");
1375
+
1376
+ scheme_val = rb_str_new2("http");
1377
+ scheme_key = rb_str_new2("rack.url_scheme");
1378
+
1379
+ errors_val = rb_stderr;
1380
+ errors_key = rb_str_new2("rack.errors");
1381
+
1382
+ multithread_val = Qfalse;
1383
+ multithread_key = rb_str_new2("rack.multithread");
1384
+
1385
+ multiprocess_val = Qfalse; /* or Qtrue? I have no clue.. */
1386
+ multiprocess_key = rb_str_new2("rack.multiprocess");
1387
+
1388
+ run_once_val = Qfalse;
1389
+ run_once_key = rb_str_new2("rack.run_once");
1390
+
1391
+ script_val = rb_str_new2("");
1392
+ script_key = rb_str_new2("SCRIPT_NAME");
1393
+
1394
+ server_name_val = rb_str_new2(name);
1395
+ server_name_key = rb_str_new2("SERVER_NAME");
1396
+
1397
+ server_port_val = INT2NUM(port);
1398
+ server_port_key = rb_str_new2("SERVER_PORT");
1399
+
1400
+ server_protocol = rb_str_new2("SERVER_PROTOCOL");
1401
+ path_info = rb_str_new2("PATH_INFO");
1402
+ request_uri = rb_str_new2("REQUEST_URI");
1403
+ query_string = rb_str_new2("QUERY_STRING");
1404
+ http_fragment = rb_str_new2("HTTP_FRAGMENT");
1405
+ request_method = rb_str_new2("REQUEST_METHOD");
1406
+ rb_remote_addr = rb_str_new2("REMOTE_ADDR");
1407
+ rb_remote_port = rb_str_new2("REMOTE_PORT");
1408
+ rack_input = rb_str_new2("rack.input");
1409
+ http_connection = rb_str_new2("HTTP_CONNECTION");
1410
+
1411
+ http_user_agent = rb_str_new2("HTTP_USER_AGENT");
1412
+ }
1413
+
1414
+ static inline int
1415
+ setsig(int sig, void* handler)
1416
+ {
1417
+ struct sigaction context, ocontext;
1418
+ context.sa_handler = handler;
1419
+ sigemptyset(&context.sa_mask);
1420
+ context.sa_flags = 0;
1421
+ return sigaction(sig, &context, &ocontext);
1422
+ }
1423
+
1424
+ static inline void
1425
+ setup_sock(int fd)
1426
+ {
1427
+ int on = 1, r;
1428
+ r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
1429
+ assert(r == 0);
1430
+ r = fcntl(fd, F_SETFL, O_NONBLOCK);
1431
+ assert(r == 0);
1432
+ }
1433
+
1434
+ static inline void
1435
+ disable_cork(client_t *client)
1436
+ {
1437
+ int off = 0;
1438
+ int on = 1, r;
1439
+ r = setsockopt(client->fd, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
1440
+ assert(r == 0);
1441
+
1442
+ r = setsockopt(client->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
1443
+ assert(r == 0);
1444
+ }
1445
+
1446
+ static inline client_t *
1447
+ new_client_t(int client_fd, struct sockaddr_in client_addr){
1448
+ client_t *client;
1449
+
1450
+ client = ruby_xmalloc(sizeof(client_t));
1451
+ memset(client, 0, sizeof(client_t));
1452
+
1453
+ /* printf("size %d\n", sizeof(client_t)); */
1454
+
1455
+ client->fd = client_fd;
1456
+
1457
+ client->remote_addr = inet_ntoa(client_addr.sin_addr);
1458
+ client->remote_port = ntohs(client_addr.sin_port);
1459
+ client->req = new_request();
1460
+ client->body_type = BODY_TYPE_NONE;
1461
+ //printf("input_buf_size %d\n", client->input_buf_size);
1462
+ return client;
1463
+ }
1464
+
1465
+ static inline void
1466
+ clean_cli(client_t *client)
1467
+ {
1468
+ write_access_log(client, log_fd, log_path);
1469
+ if(client->req){
1470
+ free_request(client->req);
1471
+ client->req = NULL;
1472
+ }
1473
+
1474
+ if(client->http != NULL){
1475
+ ruby_xfree(client->http);
1476
+ client->http = NULL;
1477
+ }
1478
+ }
1479
+
1480
+ static inline void
1481
+ close_conn(client_t *cli, picoev_loop* loop)
1482
+ {
1483
+ if(!cli->keep_alive){
1484
+ picoev_del(loop, cli->fd);
1485
+ clean_cli(cli);
1486
+ close(cli->fd);
1487
+ #ifdef DEBUG
1488
+ printf("close fd %d \n", cli->fd);
1489
+ #endif
1490
+ ruby_xfree(cli);
1491
+ }else{
1492
+ clean_cli(cli);
1493
+ disable_cork(cli);
1494
+ cli->keep_alive = 1;
1495
+ cli->environ = NULL;
1496
+ cli->http_status = NULL;
1497
+ cli->headers = NULL;
1498
+ cli->header_done = 0;
1499
+ cli->body_type = BODY_TYPE_NONE;
1500
+ cli->status_code = 0;
1501
+ cli->response = NULL;
1502
+ cli->content_length_set = 0;
1503
+ cli->content_length = 0;
1504
+ cli->write_bytes = 0;
1505
+ cli->response_closed = 0;
1506
+ cli->bad_request_code = 0;
1507
+ init_parser(cli, server_name, server_port);
1508
+ }
1509
+ }
1510
+
1511
+ static inline int
1512
+ process_rack_app(client_t *cli)
1513
+ {
1514
+ VALUE args = NULL;
1515
+ char *status;
1516
+
1517
+ args = cli->environ;
1518
+
1519
+ // cli->response = [200, {}, []]
1520
+ cli->response = rb_funcall(rack_app, i_call, 1, args);
1521
+
1522
+ if(TYPE(cli->response) != T_ARRAY || RARRAY_LEN(cli->response) < 3) {
1523
+ return 0;
1524
+ }
1525
+
1526
+ VALUE* response_ary = RARRAY_PTR(cli->response);
1527
+
1528
+ if (TYPE(response_ary[0])!=T_FIXNUM ||
1529
+ TYPE(response_ary[1])!=T_HASH ||
1530
+ TYPE(response_ary[2])!=T_ARRAY){
1531
+ return 0;
1532
+ }
1533
+
1534
+ cli->status_code = NUM2INT(response_ary[0]);
1535
+ cli->headers = response_ary[1];
1536
+
1537
+ errno = 0;
1538
+ /* printf("status code: %d\n", cli->status_code); */
1539
+
1540
+ char buff[256];
1541
+ sprintf(buff, "HTTP/1.1 %d\r\n", cli->status_code);
1542
+ cli->http_status = rb_str_new(buff, strlen(buff));
1543
+
1544
+ //check response
1545
+ if(cli->response && cli->response == Qnil){
1546
+ /* write_error_log(__FILE__, __LINE__); */
1547
+ rb_raise(rb_eException, "response must be a iter or sequence object");
1548
+ }
1549
+
1550
+ return 1;
1551
+ }
1552
+
1553
+ static void
1554
+ w_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
1555
+ {
1556
+ client_t *client = ( client_t *)(cb_arg);
1557
+ int ret;
1558
+ #ifdef DEBUG
1559
+ printf("call w_callback \n");
1560
+ #endif
1561
+ if ((events & PICOEV_TIMEOUT) != 0) {
1562
+ #ifdef DEBUG
1563
+ printf("** w_callback timeout ** \n");
1564
+ #endif
1565
+ //timeout
1566
+ client->keep_alive = 0;
1567
+ close_conn(client, loop);
1568
+
1569
+ } else if ((events & PICOEV_WRITE) != 0) {
1570
+ ret = process_body(client);
1571
+ picoev_set_timeout(loop, client->fd, WRITE_TIMEOUT_SECS);
1572
+ #ifdef DEBUG
1573
+ printf("process_body ret %d \n", ret);
1574
+ #endif
1575
+ if(ret != 0){
1576
+ //ok or die
1577
+ close_conn(client, loop);
1578
+ }
1579
+ }
1580
+ }
1581
+
1582
+ static inline void
1583
+ call_rack_app(client_t *client, picoev_loop* loop)
1584
+ {
1585
+ int ret;
1586
+ if(!process_rack_app(client)){
1587
+ //Internal Server Error
1588
+ client->bad_request_code = 500;
1589
+ send_error_page(client);
1590
+ close_conn(client, loop);
1591
+ return;
1592
+ }
1593
+
1594
+ ret = response_start(client);
1595
+ /* printf("response_start done: %d\n", ret); */
1596
+ switch(ret){
1597
+ case -1:
1598
+ // Internal Server Error
1599
+ client->bad_request_code = 500;
1600
+ send_error_page(client);
1601
+ close_conn(client, loop);
1602
+ return;
1603
+ case 0:
1604
+ // continue
1605
+ // set callback
1606
+ #ifdef DEBUG
1607
+ printf("set write callback %d \n", ret);
1608
+ #endif
1609
+ picoev_add(loop, client->fd, PICOEV_WRITE, WRITE_TIMEOUT_SECS, w_callback, (void *)client);
1610
+ return;
1611
+ default:
1612
+ // send OK
1613
+ close_conn(client, loop);
1614
+ }
1615
+ }
1616
+
1617
+ static inline void
1618
+ prepare_call_rack(client_t *client)
1619
+ {
1620
+ VALUE input = NULL, object = NULL, c = NULL;
1621
+ char *val;
1622
+
1623
+ object = rb_str_new2("");
1624
+ input = rb_funcall(StringIO, i_new, 1, object);
1625
+ rb_hash_aset((VALUE)client->environ, rack_input, input);
1626
+ client->body = object;
1627
+
1628
+ if(is_keep_alive){
1629
+ //support keep-alive
1630
+ c = rb_hash_aref(client->environ, http_connection);
1631
+ if(c){
1632
+ val = StringValuePtr(c);
1633
+ if(!strcasecmp(val, "keep-alive")){
1634
+ client->keep_alive = 1;
1635
+ }else{
1636
+ client->keep_alive = 0;
1637
+ }
1638
+ }else{
1639
+ client->keep_alive = 0;
1640
+ }
1641
+ }
1642
+ }
1643
+
1644
+ static void
1645
+ r_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
1646
+ {
1647
+ client_t *cli = ( client_t *)(cb_arg);
1648
+ if ((events & PICOEV_TIMEOUT) != 0) {
1649
+ #ifdef DEBUG
1650
+ printf("** r_callback timeout ** \n");
1651
+ #endif
1652
+ //timeout
1653
+ cli->keep_alive = 0;
1654
+ close_conn(cli, loop);
1655
+ } else if ((events & PICOEV_READ) != 0) {
1656
+ #ifdef DEBUG
1657
+ printf("ready read \n");
1658
+ #endif
1659
+ /* update timeout, and read */
1660
+ int finish = 0, nread;
1661
+ char buf[INPUT_BUF_SIZE];
1662
+ ssize_t r;
1663
+ if(!cli->keep_alive){
1664
+ picoev_set_timeout(loop, cli->fd, SHORT_TIMEOUT_SECS);
1665
+ }
1666
+ r = read(cli->fd, buf, sizeof(buf));
1667
+ switch (r) {
1668
+ case 0:
1669
+ finish = 1;
1670
+ break;
1671
+ case -1: /* error */
1672
+ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* try again later */
1673
+ break;
1674
+ } else { /* fatal error */
1675
+ rb_raise(rb_eException, "fatal error");
1676
+ // TODO:
1677
+ // raise exception from errno
1678
+ /* rb_raise(); */
1679
+ /* write_error_log(__FILE__, __LINE__); */
1680
+ cli->keep_alive = 0;
1681
+ cli->status_code = 500;
1682
+ close_conn(cli, loop);
1683
+ return;
1684
+ }
1685
+ break;
1686
+ default:
1687
+ #ifdef DEBUG
1688
+ printf("read request fd %d bufsize %d \n", cli->fd, r);
1689
+ #endif
1690
+ nread = execute_parse(cli, buf, r);
1691
+
1692
+ if(cli->bad_request_code > 0){
1693
+ #ifdef DEBUG
1694
+ printf("fd %d bad_request code %d \n", cli->fd, cli->bad_request_code);
1695
+ #endif
1696
+ send_error_page(cli);
1697
+ close_conn(cli, loop);
1698
+ return;
1699
+ }
1700
+ if( nread != r ){
1701
+ // parse error
1702
+ #ifdef DEBUG
1703
+ printf("fd %d parse error %d \n", cli->fd, cli->bad_request_code);
1704
+ #endif
1705
+ cli->bad_request_code = 400;
1706
+ send_error_page(cli);
1707
+ close_conn(cli, loop);
1708
+ return;
1709
+ }
1710
+ #ifdef DEBUG
1711
+ printf("parse ok, fd %d %d nread \n", cli->fd, nread);
1712
+ #endif
1713
+ if(parser_finish(cli) > 0){
1714
+ finish = 1;
1715
+ }
1716
+ break;
1717
+ }
1718
+
1719
+ if(finish == 1){
1720
+ prepare_call_rack(cli);
1721
+ call_rack_app(cli, loop);
1722
+ return;
1723
+ }
1724
+ }
1725
+ }
1726
+
1727
+ // TODO: use accept4 in linux
1728
+ static void
1729
+ accept_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
1730
+ {
1731
+ int client_fd;
1732
+ client_t *client;
1733
+ struct sockaddr_in client_addr;
1734
+ if ((events & PICOEV_TIMEOUT) != 0) {
1735
+ // time out
1736
+ // next turn or other process
1737
+ return;
1738
+ }else if ((events & PICOEV_READ) != 0) {
1739
+ socklen_t client_len = sizeof(client_addr);
1740
+ client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
1741
+
1742
+ if (client_fd != -1) {
1743
+ #ifdef DEBUG
1744
+ printf("accept fd %d \n", client_fd);
1745
+ #endif
1746
+ setup_sock(client_fd);
1747
+ client = new_client_t(client_fd, client_addr);
1748
+
1749
+ client->environ = Qnil;
1750
+ rb_gc_register_address(&client->environ);
1751
+
1752
+ init_parser(client, server_name, server_port);
1753
+
1754
+ picoev_add(loop, client_fd, PICOEV_READ, READ_LONG_TIMEOUT_SECS, r_callback, (void *)client);
1755
+ }else{
1756
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
1757
+ // TODO:
1758
+ // raise exception from errno
1759
+ /* rb_raise(); */
1760
+ /* write_error_log(__FILE__, __LINE__); */
1761
+ // die
1762
+ loop_done = 0;
1763
+ }
1764
+ }
1765
+ }
1766
+ }
1767
+
1768
+ static inline void
1769
+ setup_server_env(void)
1770
+ {
1771
+ setup_sock(listen_sock);
1772
+ cache_time_init();
1773
+
1774
+ setup_static_env(server_name, server_port);
1775
+ }
1776
+
1777
+ static inline int
1778
+ inet_listen(void)
1779
+ {
1780
+ struct addrinfo hints, *servinfo, *p;
1781
+ int flag = 1;
1782
+ int rv;
1783
+ char strport[7];
1784
+
1785
+ memset(&hints, 0, sizeof hints);
1786
+ hints.ai_family = AF_UNSPEC;
1787
+ hints.ai_socktype = SOCK_STREAM;
1788
+ hints.ai_flags = AI_PASSIVE;
1789
+
1790
+ snprintf(strport, sizeof (strport), "%d", server_port);
1791
+
1792
+ if ((rv = getaddrinfo(server_name, strport, &hints, &servinfo)) == -1) {
1793
+ // TODO:
1794
+ // raise exception from errno
1795
+ /* rb_raise(); */
1796
+ return -1;
1797
+ }
1798
+
1799
+ // loop through all the results and bind to the first we can
1800
+ for(p = servinfo; p != NULL; p = p->ai_next) {
1801
+ if ((listen_sock = socket(p->ai_family, p->ai_socktype,
1802
+ p->ai_protocol)) == -1) {
1803
+ //perror("server: socket");
1804
+ continue;
1805
+ }
1806
+
1807
+ if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &flag,
1808
+ sizeof(int)) == -1) {
1809
+ close(listen_sock);
1810
+ // TODO:
1811
+ // raise exception from errno
1812
+ /* rb_raise(); */
1813
+ return -1;
1814
+ }
1815
+
1816
+ if (bind(listen_sock, p->ai_addr, p->ai_addrlen) == -1) {
1817
+ close(listen_sock);
1818
+ // TODO:
1819
+ // raise exception from errno
1820
+ /* rb_raise(); */
1821
+ return -1;
1822
+ }
1823
+ break;
1824
+ }
1825
+
1826
+ if (p == NULL) {
1827
+ close(listen_sock);
1828
+ rb_raise(rb_eIOError, "server: failed to bind\n");
1829
+ return -1;
1830
+ }
1831
+
1832
+ freeaddrinfo(servinfo); // all done with this structure
1833
+
1834
+ // BACKLOG 1024
1835
+ if (listen(listen_sock, BACKLOG) == -1) {
1836
+ close(listen_sock);
1837
+ // TODO:
1838
+ // raise exception from errno
1839
+ /* rb_raise(); */
1840
+ return -1;
1841
+ }
1842
+ setup_server_env();
1843
+ return 1;
1844
+ }
1845
+
1846
+ static void
1847
+ sigint_cb(int signum)
1848
+ {
1849
+ loop_done = 0;
1850
+ /* rb_interrupt(); */
1851
+ }
1852
+
1853
+ static void
1854
+ sigpipe_cb(int signum)
1855
+ {
1856
+ }
1857
+
1858
+ static VALUE
1859
+ bossan_stop(VALUE self)
1860
+ {
1861
+ loop_done = 0;
1862
+ return Qnil;
1863
+ }
1864
+
1865
+ static VALUE
1866
+ bossan_access_log(VALUE self, VALUE args)
1867
+ {
1868
+ log_path = StringValuePtr(args);
1869
+
1870
+ if(log_fd > 0){
1871
+ close(log_fd);
1872
+ }
1873
+ log_fd = open_log_file(log_path);
1874
+
1875
+ if(log_fd < 0){
1876
+ rb_raise(rb_eTypeError, "not open file. %s", log_path);
1877
+ }
1878
+ return Qnil;
1879
+ }
1880
+
1881
+ // Bossan.run('127.0.0.1', 8000) do |env|
1882
+ // ...
1883
+ // end
1884
+ static VALUE
1885
+ bossan_run_loop(VALUE self, VALUE args1, VALUE args2, VALUE args3)
1886
+ {
1887
+ int ret;
1888
+
1889
+ if(listen_sock > 0){
1890
+ rb_raise(rb_eException, "already set listen socket");
1891
+ }
1892
+
1893
+ server_name = StringValuePtr(args1);
1894
+ server_port = NUM2INT(args2);
1895
+
1896
+ long _port = NUM2INT(args2);
1897
+
1898
+ if (_port <= 0 || _port >= 65536) {
1899
+ // out of range
1900
+ rb_raise(rb_eArgError, "port number outside valid range");
1901
+ }
1902
+
1903
+ server_port = (short)_port;
1904
+
1905
+ ret = inet_listen();
1906
+
1907
+ if(ret < 0){
1908
+ //error
1909
+ listen_sock = -1;
1910
+ }
1911
+
1912
+ rack_app = args3;
1913
+
1914
+ if(listen_sock <= 0){
1915
+ rb_raise(rb_eTypeError, "not found listen socket");
1916
+ }
1917
+
1918
+ /* init picoev */
1919
+ picoev_init(MAX_FDS);
1920
+ /* create loop */
1921
+ main_loop = picoev_create_loop(60);
1922
+ loop_done = 1;
1923
+
1924
+ setsig(SIGPIPE, sigpipe_cb);
1925
+ setsig(SIGINT, sigint_cb);
1926
+ setsig(SIGTERM, sigint_cb);
1927
+
1928
+ picoev_add(main_loop, listen_sock, PICOEV_READ, ACCEPT_TIMEOUT_SECS, accept_callback, NULL);
1929
+
1930
+ /* loop */
1931
+ while (loop_done) {
1932
+ picoev_loop_once(main_loop, 10);
1933
+ }
1934
+ picoev_destroy_loop(main_loop);
1935
+ picoev_deinit();
1936
+
1937
+ printf("Bye.\n");
1938
+ return Qnil;
1939
+ }
1940
+
1941
+ VALUE
1942
+ bossan_set_max_content_length(VALUE self, VALUE args)
1943
+ {
1944
+ max_content_length = NUM2INT(args);
1945
+ return Qnil;
1946
+ }
1947
+
1948
+ VALUE
1949
+ bossan_get_max_content_length(VALUE self)
1950
+ {
1951
+ return INT2NUM(max_content_length);
1952
+ }
1953
+
1954
+ void
1955
+ Init_bossan_ext(void)
1956
+ {
1957
+ rb_gc_register_address(&version_key);
1958
+ rb_gc_register_address(&version_val);
1959
+ rb_gc_register_address(&scheme_key);
1960
+ rb_gc_register_address(&scheme_val);
1961
+ rb_gc_register_address(&errors_key);
1962
+ rb_gc_register_address(&errors_val);
1963
+ rb_gc_register_address(&multithread_key);
1964
+ rb_gc_register_address(&multithread_val);
1965
+ rb_gc_register_address(&multiprocess_key);
1966
+ rb_gc_register_address(&multiprocess_val);
1967
+ rb_gc_register_address(&run_once_key);
1968
+ rb_gc_register_address(&run_once_val);
1969
+
1970
+ rb_gc_register_address(&script_key);
1971
+ rb_gc_register_address(&script_val);
1972
+ rb_gc_register_address(&server_name_key);
1973
+ rb_gc_register_address(&server_name_val);
1974
+ rb_gc_register_address(&server_port_key);
1975
+ rb_gc_register_address(&server_port_val);
1976
+
1977
+ rb_gc_register_address(&server_protocol);
1978
+ rb_gc_register_address(&path_info);
1979
+ rb_gc_register_address(&request_uri);
1980
+ rb_gc_register_address(&query_string);
1981
+ rb_gc_register_address(&http_fragment);
1982
+ rb_gc_register_address(&request_method);
1983
+ rb_gc_register_address(&rb_remote_addr);
1984
+ rb_gc_register_address(&rb_remote_port);
1985
+ rb_gc_register_address(&rack_input);
1986
+ rb_gc_register_address(&http_connection);
1987
+
1988
+ rb_gc_register_address(&http_user_agent);
1989
+
1990
+ rb_gc_register_address(&i_keys);
1991
+ rb_gc_register_address(&i_call);
1992
+ rb_gc_register_address(&i_new);
1993
+
1994
+ rb_gc_register_address(&rack_app); //rack app
1995
+
1996
+ i_new = rb_intern("new");
1997
+ i_call = rb_intern("call");
1998
+ i_keys = rb_intern("keys");
1999
+
2000
+ server = rb_define_module("Bossan");
2001
+ rb_gc_register_address(&server);
2002
+
2003
+ rb_define_module_function(server, "run", bossan_run_loop, 3);
2004
+ rb_define_module_function(server, "stop", bossan_stop, 0);
2005
+
2006
+ rb_define_module_function(server, "access_log", bossan_access_log, 1);
2007
+ rb_define_module_function(server, "set_max_content_length", bossan_set_max_content_length, 1);
2008
+ rb_define_module_function(server, "get_max_content_length", bossan_get_max_content_length, 0);
2009
+
2010
+ rb_require("stringio");
2011
+ StringIO = rb_const_get(rb_cObject, rb_intern("StringIO"));
2012
+ }