opal-up 0.0.6 → 0.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e47b86e6f54cbdb8ecf23cf5b6c759127ac30a8f4f00764e39eeca57ca94e52d
4
- data.tar.gz: 6d93f3b96474fb1c18fadeb5a46083241947691470a0c3f7d36dc7025e1116de
3
+ metadata.gz: 46fd760653d3303f32429a4dfd767c4d93ac56817393785d7da35632ab2d4ad2
4
+ data.tar.gz: a809d96c97f31441dd51c8e5c87aeaee47059835718f62de3217b38348d7d111
5
5
  SHA512:
6
- metadata.gz: 25d3c86c354d50656b266995a0d235460e6d9c45b1853d33d363636e1bead3b4539b8a068fee0cbfd58b27d2160759b2f1823ae039c2ce0c15793f6a95fd0541
7
- data.tar.gz: d3a6dd3a8e854a1ba75cfc297ecb5b4153c04b3814185add67424bcfd7574538d4365aebbd1006967e798d7af155ad0b98582955eb4f8c2e1f5633448d474433
6
+ metadata.gz: 6cd09583959a4340bafda2c118a570df793884fc2813e2b93a251f26220e243910263093c3ff24ac8f9dcc337af5cf1c152f5c9a491e58a5dcc32d035ef5c545
7
+ data.tar.gz: 7e45708e9f770ea45dd463dd5bf39075d7d241fe73d0ea60d638e6d80369dec4ae16661b9187525b522440133fa0272df62ca1c982bb132737807c9e05dae6f3
data/README.md CHANGED
@@ -99,7 +99,6 @@ When using secure sockets, the -a, -c and -k options must be provided
99
99
 
100
100
  Up! implements the [Rack Spec as of Rack 3.0](https://github.com/rack/rack/blob/main/SPEC.rdoc) with the following differences:
101
101
  - `rack.hijack` is not implemented, but `rack.upgrade` instead is, see "Websockets" below
102
- - `rack.input` is currently still missing
103
102
  - Tempfile support is currently incomplete, affecting a few keys in the Rack Env ('tempfile' missing in Opal).
104
103
  - Some Rack modules/classes still have issues when run in Opal and may not work as expected
105
104
 
data/ext/up_ext/up_ext.c CHANGED
@@ -37,6 +37,7 @@ static ID id_close;
37
37
  static ID id_each;
38
38
  static ID id_host;
39
39
  static ID id_logger;
40
+ static ID id_new;
40
41
  static ID id_on_close;
41
42
  static ID id_on_drained;
42
43
  static ID id_on_message;
@@ -122,6 +123,8 @@ typedef struct server_s {
122
123
  VALUE port;
123
124
  VALUE logger;
124
125
  VALUE env_template;
126
+ VALUE body;
127
+ VALUE env;
125
128
  int workers;
126
129
  int member_id;
127
130
  char secret[37];
@@ -283,6 +286,43 @@ typedef struct publish_data_s {
283
286
  server_s *s;
284
287
  } publish_data_s;
285
288
 
289
+ static void up_internal_call_app(server_s *s, uws_res_t *res, VALUE env) {
290
+ // call app
291
+ VALUE rres = rb_funcall(s->rapp, id_call, 1, env);
292
+
293
+ if (TYPE(rres) != T_ARRAY)
294
+ goto response_error;
295
+
296
+ // response status
297
+ VALUE rstatus = rb_ary_entry(rres, 0);
298
+ if (!up_internal_set_response_status(res, rstatus))
299
+ goto response_error;
300
+
301
+ // collect headers
302
+ VALUE rheaders = rb_ary_entry(rres, 1);
303
+ if (TYPE(rheaders) != T_HASH)
304
+ goto response_error;
305
+ rb_hash_foreach(rheaders, up_internal_res_header_handler, (VALUE)res);
306
+
307
+ // collect response body
308
+ VALUE rparts = rb_ary_entry(rres, 2);
309
+ up_internal_collect_response_body(res, rparts);
310
+
311
+ // end response
312
+ uws_res_end_without_body(USE_SSL, res, false);
313
+
314
+ // close resources if necessary
315
+ if (rb_respond_to(rparts, id_close))
316
+ rb_funcall(rparts, id_close, 0);
317
+
318
+ return;
319
+ response_error:
320
+ fprintf(stderr, "response error\n");
321
+ uws_res_end_without_body(USE_SSL, res, false);
322
+ }
323
+
324
+ static void up_internal_abort_data(uws_res_t *res, void *arg) {}
325
+
286
326
  static void up_internal_process_publish_post_data(uws_res_t *res,
287
327
  const char *chunk,
288
328
  size_t chunk_length,
@@ -299,9 +339,22 @@ static void up_internal_process_publish_post_data(uws_res_t *res,
299
339
  break;
300
340
  }
301
341
  }
302
- if (channel_length > 0 && message_length > 0) {
342
+ if (channel_length > 0 && message_length > 0)
303
343
  uws_publish(USE_SSL, s->app, channel_start, channel_length, message_start,
304
344
  message_length, TEXT, false);
345
+ }
346
+
347
+ static void up_internal_process_post_data(uws_res_t *res, const char *chunk,
348
+ size_t chunk_length, bool is_end,
349
+ void *arg) {
350
+ server_s *s = (server_s *)arg;
351
+ rb_str_cat(s->body, chunk, chunk_length);
352
+ if (is_end) {
353
+ // set rack.input
354
+ rb_hash_aset(s->env, rack_input, rb_funcall(cStringIO, id_new, 1, s->body));
355
+ up_internal_call_app(s, res, s->env);
356
+ s->body = Qnil;
357
+ s->env = Qnil;
305
358
  }
306
359
  }
307
360
 
@@ -322,48 +375,25 @@ static void up_internal_publish_handler(uws_res_t *res, uws_req_t *req,
322
375
  }
323
376
  }
324
377
 
325
- static void up_server_request_handler(uws_res_t *res, uws_req_t *req,
326
- void *arg) {
378
+ static void up_server_any_handler(uws_res_t *res, uws_req_t *req, void *arg) {
327
379
  // prepare rack env
328
380
  server_s *s = (server_s *)arg;
329
- VALUE renv = rb_hash_dup(s->env_template);
330
- up_server_prepare_env(renv, req);
331
-
332
- // call app
333
- VALUE rres = rb_funcall(s->rapp, id_call, 1, renv);
334
- if (TYPE(rres) != T_ARRAY)
335
- goto response_error;
336
-
337
- // response status
338
- VALUE rstatus = rb_ary_entry(rres, 0);
339
- if (!up_internal_set_response_status(res, rstatus))
340
- goto response_error;
341
-
342
- // collect headers
343
- VALUE rheaders = rb_ary_entry(rres, 1);
344
- if (TYPE(rheaders) != T_HASH)
345
- goto response_error;
346
- rb_hash_foreach(rheaders, up_internal_res_header_handler, (VALUE)res);
347
-
348
- // collect response body
349
- VALUE rparts = rb_ary_entry(rres, 2);
350
- up_internal_collect_response_body(res, rparts);
351
-
352
- // end response
353
- uws_res_end_without_body(USE_SSL, res, false);
381
+ VALUE env = rb_hash_dup(s->env_template);
382
+ up_server_prepare_env(env, req);
383
+ up_internal_call_app(s, res, env);
384
+ RB_GC_GUARD(env);
385
+ }
354
386
 
355
- // close resources if necessary
356
- if (rb_respond_to(rparts, id_close))
357
- rb_funcall(rparts, id_close, 0);
387
+ static void up_server_post_handler(uws_res_t *res, uws_req_t *req, void *arg) {
388
+ // prepare rack env
389
+ server_s *s = (server_s *)arg;
390
+ s->env = rb_hash_dup(s->env_template);
391
+ up_server_prepare_env(s->env, req);
358
392
 
359
- return;
360
- RB_GC_GUARD(rstatus);
361
- RB_GC_GUARD(rheaders);
362
- RB_GC_GUARD(rres);
363
- RB_GC_GUARD(renv);
364
- response_error:
365
- fprintf(stderr, "response error\n");
366
- uws_res_end_without_body(USE_SSL, res, false);
393
+ // receive POST data
394
+ s->body = rb_enc_str_new("", 0, utf8_encoding);
395
+ uws_res_on_data(USE_SSL, res, up_internal_process_post_data, (void *)s);
396
+ uws_res_on_aborted(USE_SSL, res, up_internal_abort_data, NULL);
367
397
  }
368
398
 
369
399
  static void
@@ -613,8 +643,8 @@ void up_ws_drain_handler(uws_websocket_t *ws, void *user_data) {
613
643
 
614
644
  void up_ws_ping_handler(uws_websocket_t *ws, const char *message, size_t length,
615
645
  void *user_data) {
616
- /* You don't need to handle this one, we automatically respond to pings as per
617
- * standard */
646
+ /* You don't need to handle this one, we automatically respond to pings as
647
+ * per standard */
618
648
  }
619
649
 
620
650
  void up_ws_pong_handler(uws_websocket_t *ws, const char *message, size_t length,
@@ -807,7 +837,8 @@ static VALUE up_server_listen(VALUE self) {
807
837
  sigemptyset(&upclcl.sa_mask);
808
838
  sigaction(SIGINT, &upclcl, NULL);
809
839
  }
810
- uws_app_any(USE_SSL, s->app, "/*", up_server_request_handler, (void *)s);
840
+ uws_app_post(USE_SSL, s->app, "/*", up_server_post_handler, (void *)s);
841
+ uws_app_any(USE_SSL, s->app, "/*", up_server_any_handler, (void *)s);
811
842
  uws_ws(USE_SSL, s->app, "/*",
812
843
  (uws_socket_behavior_t){.compression = DISABLED,
813
844
  .maxPayloadLength = 5 * 1024 * 1024,
@@ -949,6 +980,7 @@ void Init_up_ext(void) {
949
980
  id_each = rb_intern("each");
950
981
  id_host = rb_intern("host");
951
982
  id_logger = rb_intern("logger");
983
+ id_new = rb_intern("new");
952
984
  id_on_close = rb_intern("on_close");
953
985
  id_on_drained = rb_intern("on_drained");
954
986
  id_on_message = rb_intern("on_message");
@@ -980,14 +1012,14 @@ void Init_up_ext(void) {
980
1012
  rb_gc_register_address(&cLogger);
981
1013
  cLogger = rb_const_get(rb_cObject, rb_intern("Logger"));
982
1014
  rb_gc_register_address(&default_logger);
983
- default_logger = rb_funcall(cLogger, rb_intern("new"), 1, rb_stderr);
1015
+ default_logger = rb_funcall(cLogger, id_new, 1, rb_stderr);
984
1016
 
985
1017
  rb_require("stringio");
986
1018
 
987
1019
  rb_gc_register_address(&cStringIO);
988
1020
  cStringIO = rb_const_get(rb_cObject, rb_intern("StringIO"));
989
1021
  rb_gc_register_address(&default_input);
990
- default_input = rb_funcall(cStringIO, rb_intern("new"), 1, empty_string);
1022
+ default_input = rb_funcall(cStringIO, id_new, 1, empty_string);
991
1023
 
992
1024
  up_setup_rack_env_template();
993
1025
 
data/lib/up/bun/server.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # backtick_javascript: true
2
2
  require 'logger'
3
+ require 'stringio'
3
4
  require 'up/cli'
4
5
  require 'up/client'
5
6
 
@@ -23,7 +24,7 @@ module Up
23
24
  @ca_file = ca_file
24
25
  @cert_file = cert_file
25
26
  @key_file = key_file
26
- @default_input = IO.new
27
+ @default_input = StringIO.new('', 'r')
27
28
  @server = nil
28
29
  @logger = logger
29
30
  @t_factory = proc { |filename, _content_type| File.new(filename, 'a+') }
@@ -65,11 +66,17 @@ module Up
65
66
  port: #@port,
66
67
  hostname: #@host,
67
68
  development: false,
68
- fetch(req, server) {
69
+ async fetch(req, server) {
69
70
  const upgrade = req.headers.get('Upgrade');
70
71
  const env = new Map();
71
72
  env.set('rack.errors',#{STDERR});
72
- env.set('rack.input', #@default_input);
73
+ if (req.method === 'POST') {
74
+ let body = await req.text();
75
+ console.log('received: ', body);
76
+ env.set('rack.input', #{StringIO.new(`body`)});
77
+ } else {
78
+ env.set('rack.input', #@default_input);
79
+ }
73
80
  env.set('rack.logger', #@logger);
74
81
  env.set('rack.multipart.buffer_size', 4096);
75
82
  env.set('rack.multipart.tempfile_factory', #@t_factory);
@@ -1,5 +1,6 @@
1
1
  # backtick_javascript: true
2
2
  require 'logger'
3
+ require 'stringio'
3
4
  require 'up/cli'
4
5
  require 'up/client'
5
6
 
@@ -29,7 +30,7 @@ module Up
29
30
  @ca_file = ca_file
30
31
  @cert_file = cert_file
31
32
  @key_file = key_file
32
- @default_input = IO.new
33
+ @default_input = StringIO.new('', 'r')
33
34
  @server = nil
34
35
  @logger = logger
35
36
  @t_factory = proc { |filename, _content_type| File.new(filename, 'a+') }
@@ -58,20 +59,20 @@ module Up
58
59
  #{`parts`.close if `parts`.respond_to?(:close)}
59
60
  }
60
61
 
61
- self.prepare_env = function(req) {
62
+ self.prepare_env = function(req, ins) {
62
63
  const env = new Map();
63
64
  env.set('rack.errors',#{STDERR});
64
- env.set('rack.input', #@default_input);
65
- env.set('rack.logger', #@logger);
65
+ env.set('rack.input', ins.default_input);
66
+ env.set('rack.logger', ins.logger);
66
67
  env.set('rack.multipart.buffer_size', 4096);
67
- env.set('rack.multipart.tempfile_factory', #@t_factory);
68
- env.set('rack.url_scheme', #@scheme);
68
+ env.set('rack.multipart.tempfile_factory', ins.t_factory);
69
+ env.set('rack.url_scheme', ins.scheme);
69
70
  env.set('SCRIPT_NAME', "");
70
71
  env.set('SERVER_PROTOCOL', 'HTTP/1.1');
71
72
  env.set('HTTP_VERSION', 'HTTP/1.1');
72
- env.set('SERVER_NAME', #@host);
73
- env.set('SERVER_PORT', #@port);
74
- env.set('QUERY_STRING', req.getQuery());
73
+ env.set('SERVER_NAME', ins.host);
74
+ env.set('SERVER_PORT', ins.port);
75
+ env.set('QUERY_STRING', req.getQuery() || '');
75
76
  env.set('REQUEST_METHOD', req.getMethod().toUpperCase());
76
77
  env.set('PATH_INFO', req.getUrl());
77
78
  req.forEach((k, v) => { env.set('HTTP_' + k.toUpperCase().replaceAll('-', '_'), v) });
@@ -91,8 +92,24 @@ module Up
91
92
  } else {
92
93
  #@server = uws.App();
93
94
  }
95
+ #@server.post('/*', (res, req) => {
96
+ const env = ouws.prepare_env(req, self);
97
+ let buffer = Buffer.from('');
98
+ res.onData((chunk, is_last) => {
99
+ buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
100
+ if (is_last === true) {
101
+ env.set('rack.input', #{StringIO.new(`buffer.toString()`)});
102
+ const rack_res = #@app.$call(env);
103
+ res.writeStatus(rack_res[0].toString() + ' OK');
104
+ ouws.handle_headers(rack_res[1], res);
105
+ ouws.handle_response(rack_res[2], res);
106
+ res.end();
107
+ }
108
+ });
109
+ res.onAborted(() => {});
110
+ });
94
111
  #@server.any('/*', (res, req) => {
95
- const rack_res = #@app.$call(ouws.prepare_env(req));
112
+ const rack_res = #@app.$call(ouws.prepare_env(req, self));
96
113
  res.writeStatus(rack_res[0].toString() + ' OK');
97
114
  ouws.handle_headers(rack_res[1], res);
98
115
  ouws.handle_response(rack_res[2], res);
@@ -136,7 +153,7 @@ module Up
136
153
  },
137
154
  sendPingsAutomatically: true,
138
155
  upgrade: (res, req, context) => {
139
- const env = ouws.prepare_env(req);
156
+ const env = ouws.prepare_env(req, self);
140
157
  env.set('rack.upgrade?', #{:websocket});
141
158
  const rack_res = #@app.$call(env);
142
159
  const handler = env.get('rack.upgrade');
data/lib/up/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Up
2
- VERSION = '0.0.6'.freeze
2
+ VERSION = '0.0.7'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-up
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann