bossan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }