rage-iodine 5.4.0 → 5.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/Gemfile +2 -1
- data/ext/iodine/fio.c +97 -0
- data/ext/iodine/fio.h +13 -0
- data/ext/iodine/http.c +23 -3
- data/ext/iodine/http_internal.c +7 -5
- data/ext/iodine/iodine.c +3 -0
- data/ext/iodine/iodine.h +1 -0
- data/ext/iodine/iodine_caller.c +14 -0
- data/ext/iodine/iodine_caller.h +2 -0
- data/ext/iodine/iodine_defer.c +8 -1
- data/ext/iodine/iodine_http.c +29 -4
- data/ext/iodine/iodine_perf.c +28 -0
- data/ext/iodine/iodine_perf.h +6 -0
- data/lib/iodine/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ffa46cab7e0fb7fc7550dd142f42b0850287fee60cc0d72b7f52757f52720f7
|
|
4
|
+
data.tar.gz: c51b8ad9e316c21ed06e6803dcfb5af7bf70fc3eee84a0fd179b2730d2572473
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa99ee4e7abb10b55b6f14aeeaef6bf03e85cf8aff9b33a66f7b4f64097c5ef824e0c3de6663caf00f5404b2d08b663debb60c796a0a44490138a96ac92a832c
|
|
7
|
+
data.tar.gz: ca2a4ac6f633955b202dccf09661cb7799ae92e16078ef3776c1648e18e2b1ab620f470f4b99b3c75b7d0e8f9b064fad180fd5c9b32ab6ae0ddd60c9d601b58d
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
|
6
6
|
|
|
7
7
|
## Changes:
|
|
8
8
|
|
|
9
|
+
#### Change log v.5.6.0 (2026-09-06)
|
|
10
|
+
|
|
11
|
+
**Update**: TCP Socket Listen: Accept Queue
|
|
12
|
+
|
|
13
|
+
#### Change log v.5.5.0 (2026-07-06)
|
|
14
|
+
|
|
15
|
+
**Update**: Update `pre_start` callbacks to fail the server launch in case of errors
|
|
16
|
+
|
|
17
|
+
**Update**: Update media types in the MIME table
|
|
18
|
+
|
|
19
|
+
**Update**: Ensure users can override headers when serving files
|
|
20
|
+
|
|
21
|
+
**Update**: Support `x-sendfile-root` headers
|
|
22
|
+
|
|
9
23
|
#### Change log v.5.4.0 (2026-06-08)
|
|
10
24
|
|
|
11
25
|
**Update**: Optimize `fio_run_every` timers
|
data/Gemfile
CHANGED
data/ext/iodine/fio.c
CHANGED
|
@@ -4532,10 +4532,22 @@ Initialize the library
|
|
|
4532
4532
|
|
|
4533
4533
|
static void fio_pubsub_on_fork(void);
|
|
4534
4534
|
|
|
4535
|
+
#if defined(__linux__)
|
|
4536
|
+
/* accept-queue tracking lock for the listener registry (defined alongside
|
|
4537
|
+
* fio_accept_queue_listeners in the listener section below); declared here
|
|
4538
|
+
* so fio_on_fork can reset it across children. */
|
|
4539
|
+
static fio_lock_i fio_accept_queue_lock;
|
|
4540
|
+
#endif
|
|
4541
|
+
|
|
4535
4542
|
/* Called within a child process after it starts. */
|
|
4536
4543
|
static void fio_on_fork(void) {
|
|
4537
4544
|
fio_timer_lock = FIO_LOCK_INIT;
|
|
4538
4545
|
fio_data->lock = FIO_LOCK_INIT;
|
|
4546
|
+
#if defined(__linux__)
|
|
4547
|
+
/* a forked child may inherit the accept-queue lock while a parent thread
|
|
4548
|
+
* held it mid-walk; that thread won't exist in the child, so reset it. */
|
|
4549
|
+
fio_accept_queue_lock = FIO_LOCK_INIT;
|
|
4550
|
+
#endif
|
|
4539
4551
|
fio_defer_on_fork();
|
|
4540
4552
|
fio_malloc_after_fork();
|
|
4541
4553
|
fio_poll_init();
|
|
@@ -5571,6 +5583,14 @@ The listening protocol (use the facil.io API to make a socket and attach it)
|
|
|
5571
5583
|
typedef struct {
|
|
5572
5584
|
fio_protocol_s pr;
|
|
5573
5585
|
intptr_t uuid;
|
|
5586
|
+
#if defined(__linux__)
|
|
5587
|
+
/**
|
|
5588
|
+
* Listener node adding this listener into to fio_accept_queue_listeners,
|
|
5589
|
+
* so Iodine::Perf.queued_connections can find its socket's fd and read its
|
|
5590
|
+
* kernel length accept-queue(AcceptQ):backlog where (backlog <= somaxconn) (TCP_INFO).
|
|
5591
|
+
*/
|
|
5592
|
+
fio_ls_embd_s listener_node;
|
|
5593
|
+
#endif
|
|
5574
5594
|
void *udata;
|
|
5575
5595
|
void (*on_open)(intptr_t uuid, void *udata);
|
|
5576
5596
|
void (*on_start)(intptr_t uuid, void *udata);
|
|
@@ -5582,8 +5602,20 @@ typedef struct {
|
|
|
5582
5602
|
void *tls;
|
|
5583
5603
|
} fio_listen_protocol_s;
|
|
5584
5604
|
|
|
5605
|
+
#if defined(__linux__)
|
|
5606
|
+
/* tracks iodine's listening sockets for the accept-queue backlog query.
|
|
5607
|
+
* guarded against concurrent teardown (reactor thread, no GVL) */
|
|
5608
|
+
static fio_ls_embd_s fio_accept_queue_listeners = FIO_LS_INIT(fio_accept_queue_listeners);
|
|
5609
|
+
static fio_lock_i fio_accept_queue_lock = FIO_LOCK_INIT;
|
|
5610
|
+
#endif
|
|
5611
|
+
|
|
5585
5612
|
static void fio_listen_cleanup_task(void *pr_) {
|
|
5586
5613
|
fio_listen_protocol_s *pr = pr_;
|
|
5614
|
+
#if defined(__linux__)
|
|
5615
|
+
fio_lock(&fio_accept_queue_lock);
|
|
5616
|
+
fio_ls_embd_remove(&pr->listener_node);
|
|
5617
|
+
fio_unlock(&fio_accept_queue_lock);
|
|
5618
|
+
#endif
|
|
5587
5619
|
#ifndef __MINGW32__
|
|
5588
5620
|
if (pr->tls)
|
|
5589
5621
|
fio_tls_destroy(pr->tls);
|
|
@@ -5733,6 +5765,12 @@ intptr_t fio_listen FIO_IGNORE_MACRO(struct fio_listen_args args) {
|
|
|
5733
5765
|
if (port_len)
|
|
5734
5766
|
memcpy(pr->port, args.port, port_len + 1);
|
|
5735
5767
|
|
|
5768
|
+
#if defined(__linux__)
|
|
5769
|
+
fio_lock(&fio_accept_queue_lock);
|
|
5770
|
+
fio_ls_embd_push(&fio_accept_queue_listeners, &pr->listener_node);
|
|
5771
|
+
fio_unlock(&fio_accept_queue_lock);
|
|
5772
|
+
#endif
|
|
5773
|
+
|
|
5736
5774
|
if (fio_is_running()) {
|
|
5737
5775
|
fio_attach(pr->uuid, &pr->pr);
|
|
5738
5776
|
} else {
|
|
@@ -5753,6 +5791,65 @@ error:
|
|
|
5753
5791
|
return -1;
|
|
5754
5792
|
}
|
|
5755
5793
|
|
|
5794
|
+
/* -------------------------------------------------------------------------
|
|
5795
|
+
* Kernel accept-queue(AcceptQ) which is Queue length: backlog, where backlog <= somaxconn
|
|
5796
|
+
* "backlog are established connections waiting for accept()" = sk_ack_backlog.
|
|
5797
|
+
* Returns the sum of the accept-queues of all iodine listening sockets, or 0.
|
|
5798
|
+
* ---------------------------------------------------------------------- */
|
|
5799
|
+
#if defined(__linux__)
|
|
5800
|
+
intptr_t fio_queued_connections(void) {
|
|
5801
|
+
intptr_t backlog = 0;
|
|
5802
|
+
|
|
5803
|
+
fio_lock(&fio_accept_queue_lock);
|
|
5804
|
+
/**
|
|
5805
|
+
* Walk every registered listener and sum its kernel accept-queue depth/length.
|
|
5806
|
+
* The list always begins with a permanent head node (fio_accept_queue_listeners)
|
|
5807
|
+
* that works like a fixed bookmark: it holds no listener of its own, real nodes
|
|
5808
|
+
* are chained after it, and the last node links back to it, forming a circle
|
|
5809
|
+
* i.e a circular linked list also it's a doubly linked list.
|
|
5810
|
+
*
|
|
5811
|
+
* So the loop:
|
|
5812
|
+
* - starts at `.next`, i.e. the FIRST REAL node starting at the head
|
|
5813
|
+
* itself would be wrong, since it owns no listener and converting it
|
|
5814
|
+
* with FIO_LS_EMBD_OBJ would produce a bogus pointer;
|
|
5815
|
+
* - stops when it arrives back at the head, meaning every real node
|
|
5816
|
+
* has been visited;
|
|
5817
|
+
* - runs zero times on an empty list, because a lone head simply
|
|
5818
|
+
* points at itself.
|
|
5819
|
+
*/
|
|
5820
|
+
for (fio_ls_embd_s *pos = fio_accept_queue_listeners.next; pos != &fio_accept_queue_listeners; pos = pos->next) {
|
|
5821
|
+
fio_listen_protocol_s *pr = FIO_LS_EMBD_OBJ(fio_listen_protocol_s, listener_node, pos);
|
|
5822
|
+
struct tcp_info info;
|
|
5823
|
+
socklen_t tlen = sizeof(info);
|
|
5824
|
+
int fd = fio_uuid2fd(pr->uuid);
|
|
5825
|
+
|
|
5826
|
+
fio_lock(&fd_data(fd).protocol_lock);
|
|
5827
|
+
|
|
5828
|
+
/* Skip sockets that were closed or reused before we could query them.
|
|
5829
|
+
* Callers must run this after listeners are attached (e.g. from within
|
|
5830
|
+
* Iodine.run / a background thread), so the listener's protocol slot is
|
|
5831
|
+
* populated and the checks below are meaningful. */
|
|
5832
|
+
if (!uuid_is_valid(pr->uuid) || fd_data(fd).protocol != &pr->pr) {
|
|
5833
|
+
fio_unlock(&fd_data(fd).protocol_lock);
|
|
5834
|
+
continue;
|
|
5835
|
+
}
|
|
5836
|
+
|
|
5837
|
+
int ok = !getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &tlen);
|
|
5838
|
+
|
|
5839
|
+
fio_unlock(&fd_data(fd).protocol_lock);
|
|
5840
|
+
|
|
5841
|
+
if (!ok) {
|
|
5842
|
+
continue;
|
|
5843
|
+
}
|
|
5844
|
+
|
|
5845
|
+
backlog += (intptr_t)info.tcpi_unacked;
|
|
5846
|
+
}
|
|
5847
|
+
fio_unlock(&fio_accept_queue_lock);
|
|
5848
|
+
|
|
5849
|
+
return backlog;
|
|
5850
|
+
}
|
|
5851
|
+
#endif
|
|
5852
|
+
|
|
5756
5853
|
/* *****************************************************************************
|
|
5757
5854
|
Section Start Marker
|
|
5758
5855
|
|
data/ext/iodine/fio.h
CHANGED
|
@@ -1111,6 +1111,19 @@ intptr_t fio_socket(const char *address, const char *port, uint8_t is_server);
|
|
|
1111
1111
|
*/
|
|
1112
1112
|
intptr_t fio_accept(intptr_t srv_uuid);
|
|
1113
1113
|
|
|
1114
|
+
/**
|
|
1115
|
+
* Returns the number of established connections currently parked in the
|
|
1116
|
+
* kernel's accept queue(s) (sk_ack_backlog) of all iodine listening sockets.
|
|
1117
|
+
*
|
|
1118
|
+
* The query goes straight to the kernel via getsockopt(TCP_INFO).
|
|
1119
|
+
*
|
|
1120
|
+
* Returns the total accept queue length across all iodine listeners, or 0
|
|
1121
|
+
* when there are no listeners.
|
|
1122
|
+
*/
|
|
1123
|
+
#if defined(__linux__)
|
|
1124
|
+
intptr_t fio_queued_connections(void);
|
|
1125
|
+
#endif /* linux only */
|
|
1126
|
+
|
|
1114
1127
|
/**
|
|
1115
1128
|
* Returns 1 if the uuid refers to a valid and open, socket.
|
|
1116
1129
|
*
|
data/ext/iodine/http.c
CHANGED
|
@@ -188,6 +188,26 @@ int http_set_header2(http_s *r, fio_str_info_s n, fio_str_info_s v) {
|
|
|
188
188
|
return ret;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Sets a response header if it hasn't already been set.
|
|
193
|
+
*
|
|
194
|
+
* Returns -1 on error and 0 on success.
|
|
195
|
+
*/
|
|
196
|
+
static inline int http_set_header_if_none(http_s *r, FIOBJ name, FIOBJ value) {
|
|
197
|
+
if (HTTP_INVALID_HANDLE(r) || !name) {
|
|
198
|
+
fiobj_free(value);
|
|
199
|
+
return -1;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (fiobj_hash_get2(r->private_data.out_headers, fiobj_obj2hash(name))) {
|
|
203
|
+
fiobj_free(value);
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
fiobj_hash_set(r->private_data.out_headers, name, value);
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
191
211
|
/**
|
|
192
212
|
* Sets a response cookie, taking ownership of the value object, but NOT the
|
|
193
213
|
* name object (so name objects could be reused in future responses).
|
|
@@ -461,12 +481,12 @@ no_gzip_support:
|
|
|
461
481
|
return -1;
|
|
462
482
|
found_file:
|
|
463
483
|
/* set cache-control */
|
|
464
|
-
|
|
484
|
+
http_set_header_if_none(h, HTTP_HEADER_CACHE_CONTROL, fiobj_dup(HTTP_HVALUE_MAX_AGE));
|
|
465
485
|
/* set last-modified */
|
|
466
486
|
FIOBJ last_modified_str = fiobj_str_buf(32);
|
|
467
487
|
fiobj_str_resize(
|
|
468
488
|
last_modified_str, http_time2str(fiobj_obj2cstr(last_modified_str).data, file_data.st_mtime));
|
|
469
|
-
|
|
489
|
+
http_set_header_if_none(h, HTTP_HEADER_LAST_MODIFIED, last_modified_str);
|
|
470
490
|
/* set & test etag */
|
|
471
491
|
FIOBJ etag_str = fiobj_str_buf(1);
|
|
472
492
|
fiobj_str_printf(etag_str, "%lx-%llx", file_data.st_mtime, file_data.st_size);
|
|
@@ -605,7 +625,7 @@ open_file:
|
|
|
605
625
|
tmp = http_mimetype_find(s.data + pos, s.len - pos);
|
|
606
626
|
}
|
|
607
627
|
if (tmp)
|
|
608
|
-
|
|
628
|
+
http_set_header_if_none(h, HTTP_HEADER_CONTENT_TYPE, tmp);
|
|
609
629
|
}
|
|
610
630
|
http_sendfile(h, file, length, offset);
|
|
611
631
|
return 0;
|
data/ext/iodine/http_internal.c
CHANGED
|
@@ -610,7 +610,7 @@ static void http_lib_init(void *ignr_) {
|
|
|
610
610
|
REGISTER_MIME("jpgm", "video/jpm");
|
|
611
611
|
REGISTER_MIME("jpgv", "video/jpeg");
|
|
612
612
|
REGISTER_MIME("jpm", "video/jpm");
|
|
613
|
-
REGISTER_MIME("js", "
|
|
613
|
+
REGISTER_MIME("js", "text/javascript");
|
|
614
614
|
REGISTER_MIME("json", "application/json");
|
|
615
615
|
REGISTER_MIME("jsonml", "application/jsonml+json");
|
|
616
616
|
REGISTER_MIME("kar", "audio/midi");
|
|
@@ -694,6 +694,7 @@ static void http_lib_init(void *ignr_) {
|
|
|
694
694
|
REGISTER_MIME("mie", "application/x-mie");
|
|
695
695
|
REGISTER_MIME("mif", "application/vnd.mif");
|
|
696
696
|
REGISTER_MIME("mime", "message/rfc822");
|
|
697
|
+
REGISTER_MIME("mjs", "text/javascript");
|
|
697
698
|
REGISTER_MIME("mj2", "video/mj2");
|
|
698
699
|
REGISTER_MIME("mjp2", "video/mj2");
|
|
699
700
|
REGISTER_MIME("mk3d", "video/x-matroska");
|
|
@@ -803,7 +804,7 @@ static void http_lib_init(void *ignr_) {
|
|
|
803
804
|
REGISTER_MIME("osf", "application/vnd.yamaha.openscoreformat");
|
|
804
805
|
REGISTER_MIME("osfpvg", "application/vnd.yamaha.openscoreformat.osfpvg+xml");
|
|
805
806
|
REGISTER_MIME("otc", "application/vnd.oasis.opendocument.chart-template");
|
|
806
|
-
REGISTER_MIME("otf", "
|
|
807
|
+
REGISTER_MIME("otf", "font/otf");
|
|
807
808
|
REGISTER_MIME("otg", "application/vnd.oasis.opendocument.graphics-template");
|
|
808
809
|
REGISTER_MIME("oth", "application/vnd.oasis.opendocument.text-web");
|
|
809
810
|
REGISTER_MIME("oti", "application/vnd.oasis.opendocument.image-template");
|
|
@@ -1066,8 +1067,8 @@ static void http_lib_init(void *ignr_) {
|
|
|
1066
1067
|
REGISTER_MIME("trm", "application/x-msterminal");
|
|
1067
1068
|
REGISTER_MIME("tsd", "application/timestamped-data");
|
|
1068
1069
|
REGISTER_MIME("tsv", "text/tab-separated-values");
|
|
1069
|
-
REGISTER_MIME("ttc", "
|
|
1070
|
-
REGISTER_MIME("ttf", "
|
|
1070
|
+
REGISTER_MIME("ttc", "font/collection");
|
|
1071
|
+
REGISTER_MIME("ttf", "font/ttf");
|
|
1071
1072
|
REGISTER_MIME("ttl", "text/turtle");
|
|
1072
1073
|
REGISTER_MIME("twd", "application/vnd.simtech-mindmapper");
|
|
1073
1074
|
REGISTER_MIME("twds", "application/vnd.simtech-mindmapper");
|
|
@@ -1163,7 +1164,8 @@ static void http_lib_init(void *ignr_) {
|
|
|
1163
1164
|
REGISTER_MIME("wmx", "video/x-ms-wmx");
|
|
1164
1165
|
REGISTER_MIME("wmz", "application/x-ms-wmz");
|
|
1165
1166
|
// REGISTER_MIME("wmz", "application/x-msmetafile");
|
|
1166
|
-
REGISTER_MIME("woff", "
|
|
1167
|
+
REGISTER_MIME("woff", "font/woff");
|
|
1168
|
+
REGISTER_MIME("woff2", "font/woff2");
|
|
1167
1169
|
REGISTER_MIME("wpd", "application/vnd.wordperfect");
|
|
1168
1170
|
REGISTER_MIME("wpl", "application/vnd.ms-wpl");
|
|
1169
1171
|
REGISTER_MIME("wps", "application/vnd.ms-works");
|
data/ext/iodine/iodine.c
CHANGED
|
@@ -1401,6 +1401,9 @@ void Init_iodine_ext(void) {
|
|
|
1401
1401
|
// initialize concurrency related methods
|
|
1402
1402
|
iodine_defer_initialize();
|
|
1403
1403
|
|
|
1404
|
+
// initialize performance metrics
|
|
1405
|
+
iodine_perf_initialize();
|
|
1406
|
+
|
|
1404
1407
|
// initialize the connection class
|
|
1405
1408
|
iodine_connection_init();
|
|
1406
1409
|
|
data/ext/iodine/iodine.h
CHANGED
data/ext/iodine/iodine_caller.c
CHANGED
|
@@ -152,6 +152,18 @@ static VALUE iodine_call(VALUE obj, ID method) {
|
|
|
152
152
|
return (VALUE)rv;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/** Calls a Ruby method on a given object, without protecting against exceptions. */
|
|
156
|
+
static VALUE iodine_call_unprotected(VALUE obj, ID method) {
|
|
157
|
+
iodine_rb_task_s task = {
|
|
158
|
+
.obj = obj,
|
|
159
|
+
.argc = 0,
|
|
160
|
+
.argv = NULL,
|
|
161
|
+
.method = method,
|
|
162
|
+
};
|
|
163
|
+
void *rv = iodine_enterGVL((void *(*)(void *))iodine_ruby_caller_perform, &task);
|
|
164
|
+
return (VALUE)rv;
|
|
165
|
+
}
|
|
166
|
+
|
|
155
167
|
/** Calls a Ruby method on a given object, protecting against exceptions. */
|
|
156
168
|
static VALUE iodine_call2(VALUE obj, ID method, int argc, VALUE *argv) {
|
|
157
169
|
iodine_rb_task_s task = {
|
|
@@ -223,6 +235,8 @@ struct IodineCaller_s IodineCaller = {
|
|
|
223
235
|
.call = iodine_call,
|
|
224
236
|
/** Calls a Ruby method on a given object, protecting against exceptions. */
|
|
225
237
|
.call2 = iodine_call2,
|
|
238
|
+
/** Calls a Ruby method on a given object, without protecting against exceptions. */
|
|
239
|
+
.call_unprotected = iodine_call_unprotected,
|
|
226
240
|
/** Returns the GVL state flag. */
|
|
227
241
|
.in_GVL = iodine_in_GVL,
|
|
228
242
|
/** Forces the GVL state flag. */
|
data/ext/iodine/iodine_caller.h
CHANGED
|
@@ -14,6 +14,8 @@ extern struct IodineCaller_s {
|
|
|
14
14
|
VALUE (*call)(VALUE obj, ID method);
|
|
15
15
|
/** Calls a Ruby method on a given object, protecting against exceptions. */
|
|
16
16
|
VALUE (*call2)(VALUE obj, ID method, int argc, VALUE *argv);
|
|
17
|
+
/** Calls a Ruby method on a given object, without protecting against exceptions. */
|
|
18
|
+
VALUE (*call_unprotected)(VALUE obj, ID method);
|
|
17
19
|
/** Calls a Ruby method on a given object, protecting against exceptions. */
|
|
18
20
|
VALUE(*call_with_block)
|
|
19
21
|
(VALUE obj, ID method, int argc, VALUE *argv, VALUE udata,
|
data/ext/iodine/iodine_defer.c
CHANGED
|
@@ -323,6 +323,12 @@ static void iodine_perform_state_callback_persist(void *blk_) {
|
|
|
323
323
|
IodineCaller.call(blk, call_id);
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
/* performs a Ruby state callback without protecting against exceptions */
|
|
327
|
+
static void iodine_perform_unprotected_state_callback_persist(void *blk_) {
|
|
328
|
+
VALUE blk = (VALUE)blk_;
|
|
329
|
+
IodineCaller.call_unprotected(blk, call_id);
|
|
330
|
+
}
|
|
331
|
+
|
|
326
332
|
// clang-format off
|
|
327
333
|
/**
|
|
328
334
|
Sets a block of code to run when Iodine's core state is updated.
|
|
@@ -357,7 +363,7 @@ static VALUE iodine_on_state(VALUE self, VALUE event) {
|
|
|
357
363
|
|
|
358
364
|
if (state == STATE_PRE_START) {
|
|
359
365
|
fio_state_callback_add(FIO_CALL_PRE_START,
|
|
360
|
-
|
|
366
|
+
iodine_perform_unprotected_state_callback_persist,
|
|
361
367
|
(void *)block);
|
|
362
368
|
} else if (state == STATE_BEFORE_FORK) {
|
|
363
369
|
fio_state_callback_add(FIO_CALL_BEFORE_FORK,
|
|
@@ -409,6 +415,7 @@ static void iodine_defer_on_finish(void *ignr) {
|
|
|
409
415
|
iodine_join_io_thread();
|
|
410
416
|
}
|
|
411
417
|
|
|
418
|
+
|
|
412
419
|
/* *****************************************************************************
|
|
413
420
|
Add defer API to Iodine
|
|
414
421
|
***************************************************************************** */
|
data/ext/iodine/iodine_http.c
CHANGED
|
@@ -102,6 +102,7 @@ rack_declare(CONTENT_TYPE);
|
|
|
102
102
|
rack_declare(R_URL_SCHEME); // rack.url_scheme
|
|
103
103
|
rack_declare(R_INPUT); // rack.input
|
|
104
104
|
rack_declare(XSENDFILE); // for X-Sendfile support
|
|
105
|
+
rack_declare(XSENDFILE_ROOT); // for X-Sendfile support
|
|
105
106
|
rack_declare(XSENDFILE_TYPE); // for X-Sendfile support
|
|
106
107
|
rack_declare(XSENDFILE_TYPE_HEADER); // for X-Sendfile support
|
|
107
108
|
rack_declare(CONTENT_LENGTH_HEADER); // for X-Sendfile support
|
|
@@ -112,6 +113,7 @@ rack_declare(IODINE_HAS_BODY);
|
|
|
112
113
|
typedef struct {
|
|
113
114
|
http_s *h;
|
|
114
115
|
FIOBJ body;
|
|
116
|
+
FIOBJ root;
|
|
115
117
|
enum iodine_http_response_type_enum {
|
|
116
118
|
IODINE_HTTP_NONE,
|
|
117
119
|
IODINE_HTTP_SENDBODY,
|
|
@@ -716,6 +718,14 @@ static inline void *iodine_handle_request_in_GVL(void *handle_) {
|
|
|
716
718
|
handle->body = fiobj_str_new(RSTRING_PTR(xfiles), RSTRING_LEN(xfiles));
|
|
717
719
|
handle->type = IODINE_HTTP_XSENDFILE;
|
|
718
720
|
rb_hash_delete(response_headers, XSENDFILE);
|
|
721
|
+
// extract optional root directory for path validation
|
|
722
|
+
VALUE xroot = rb_hash_aref(response_headers, XSENDFILE_ROOT);
|
|
723
|
+
if (xroot != Qnil && TYPE(xroot) == T_STRING) {
|
|
724
|
+
handle->root = fiobj_str_new(RSTRING_PTR(xroot), RSTRING_LEN(xroot));
|
|
725
|
+
rb_hash_delete(response_headers, XSENDFILE_ROOT);
|
|
726
|
+
} else {
|
|
727
|
+
handle->root = FIOBJ_INVALID;
|
|
728
|
+
}
|
|
719
729
|
// remove content length headers, as this will be controled by iodine
|
|
720
730
|
rb_hash_delete(response_headers, CONTENT_LENGTH_HEADER);
|
|
721
731
|
// review each header and write it to the response.
|
|
@@ -782,8 +792,22 @@ iodine_perform_handle_action(iodine_http_request_handle_s handle) {
|
|
|
782
792
|
.len == 7)
|
|
783
793
|
fiobj_hash_delete2(handle.h->private_data.out_headers,
|
|
784
794
|
fiobj_obj2hash(HTTP_HEADER_CONTENT_ENCODING));
|
|
785
|
-
fio_str_info_s
|
|
786
|
-
|
|
795
|
+
fio_str_info_s file_data = fiobj_obj2cstr(handle.body);
|
|
796
|
+
int err;
|
|
797
|
+
if (handle.root != FIOBJ_INVALID) {
|
|
798
|
+
/* root dir specified - treat x-sendfile as relative/encoded path */
|
|
799
|
+
fio_str_info_s root_data = fiobj_obj2cstr(handle.root);
|
|
800
|
+
err = http_sendfile2(handle.h, root_data.data, root_data.len,
|
|
801
|
+
file_data.data, file_data.len);
|
|
802
|
+
fiobj_free(handle.root);
|
|
803
|
+
} else {
|
|
804
|
+
/* no root dir - original behavior (absolute path as prefix) */
|
|
805
|
+
err = http_sendfile2(handle.h, file_data.data, file_data.len, NULL, 0);
|
|
806
|
+
}
|
|
807
|
+
if (err) {
|
|
808
|
+
fiobj_hash_clear(handle.h->private_data.out_headers);
|
|
809
|
+
http_set_header(handle.h, HTTP_HEADER_CACHE_CONTROL,
|
|
810
|
+
fiobj_str_new("no-cache, max-age=0", 19));
|
|
787
811
|
http_send_error(handle.h, 404);
|
|
788
812
|
}
|
|
789
813
|
fiobj_free(handle.body);
|
|
@@ -1181,10 +1205,11 @@ void iodine_init_http(void) {
|
|
|
1181
1205
|
rack_set(QUERY_ESTRING, "");
|
|
1182
1206
|
rack_set(R_URL_SCHEME, "rack.url_scheme");
|
|
1183
1207
|
rack_set(R_INPUT, "rack.input");
|
|
1184
|
-
rack_set(XSENDFILE, "
|
|
1208
|
+
rack_set(XSENDFILE, "x-sendfile");
|
|
1209
|
+
rack_set(XSENDFILE_ROOT, "x-sendfile-root");
|
|
1185
1210
|
rack_set(XSENDFILE_TYPE, "sendfile.type");
|
|
1186
1211
|
rack_set(XSENDFILE_TYPE_HEADER, "HTTP_X_SENDFILE_TYPE");
|
|
1187
|
-
rack_set(CONTENT_LENGTH_HEADER, "
|
|
1212
|
+
rack_set(CONTENT_LENGTH_HEADER, "content-length");
|
|
1188
1213
|
|
|
1189
1214
|
rack_set(IODINE_R_INPUT, "rack.input");
|
|
1190
1215
|
rack_set(IODINE_R_HIJACK_IO, "rack.hijack_io");
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#include "iodine.h"
|
|
2
|
+
|
|
3
|
+
/* *****************************************************************************
|
|
4
|
+
Performance metrics
|
|
5
|
+
***************************************************************************** */
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Iodine::Perf.queued_connections
|
|
9
|
+
*
|
|
10
|
+
* Returns the total number of established connections currently parked in
|
|
11
|
+
* the kernel's accept queue(s) (sk_ack_backlog) for all iodine listening
|
|
12
|
+
* sockets. Returns 0 when there are no listeners and nil on non-Linux systems.
|
|
13
|
+
*/
|
|
14
|
+
static VALUE iodine_perf_queued_connections(VALUE self) {
|
|
15
|
+
(void)self;
|
|
16
|
+
#if defined(__linux__)
|
|
17
|
+
intptr_t backlog = fio_queued_connections();
|
|
18
|
+
return INT2NUM((long)backlog);
|
|
19
|
+
#else
|
|
20
|
+
return Qnil;
|
|
21
|
+
#endif
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
void iodine_perf_initialize(void) {
|
|
25
|
+
VALUE IodinePerfModule = rb_define_module_under(IodineModule, "Perf");
|
|
26
|
+
rb_define_module_function(IodinePerfModule, "queued_connections",
|
|
27
|
+
iodine_perf_queued_connections, 0);
|
|
28
|
+
}
|
data/lib/iodine/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rage-iodine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Boaz Segev
|
|
@@ -217,6 +217,8 @@ files:
|
|
|
217
217
|
- ext/iodine/iodine_json.h
|
|
218
218
|
- ext/iodine/iodine_mustache.c
|
|
219
219
|
- ext/iodine/iodine_mustache.h
|
|
220
|
+
- ext/iodine/iodine_perf.c
|
|
221
|
+
- ext/iodine/iodine_perf.h
|
|
220
222
|
- ext/iodine/iodine_pubsub.c
|
|
221
223
|
- ext/iodine/iodine_pubsub.h
|
|
222
224
|
- ext/iodine/iodine_rack_io.c
|