ruby-lsapi 5.7 → 5.9
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/README +11 -2
- data/examples/lsapi_with_cgi.rb +17 -2
- data/examples/testlsapi.rb +18 -1
- data/ext/lsapi/lsapilib.c +638 -204
- data/ext/lsapi/lsapilib.h +26 -5
- data/ext/lsapi/lsruby.c +394 -205
- data/lsapi.gemspec +2 -4
- data/rails/dispatch.lsapi +30 -2
- data/scripts/lsruby_runner.rb +33 -10
- metadata +3 -6
data/ext/lsapi/lsruby.c
CHANGED
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
#endif
|
|
13
13
|
|
|
14
14
|
#include "lsapilib.h"
|
|
15
|
+
#include <ctype.h>
|
|
15
16
|
#include <errno.h>
|
|
17
|
+
#include <inttypes.h>
|
|
18
|
+
#include <limits.h>
|
|
16
19
|
#include <netinet/in.h>
|
|
17
20
|
#include <netinet/tcp.h>
|
|
18
21
|
#include <signal.h>
|
|
22
|
+
#include <stdint.h>
|
|
23
|
+
#include <stdio.h>
|
|
24
|
+
#include <stdlib.h>
|
|
25
|
+
#include <string.h>
|
|
19
26
|
#include <sys/socket.h>
|
|
20
27
|
#include <sys/wait.h>
|
|
21
28
|
#include <unistd.h>
|
|
@@ -46,7 +53,7 @@ static VALUE env_copy;
|
|
|
46
53
|
|
|
47
54
|
static VALUE lsapi_env;
|
|
48
55
|
|
|
49
|
-
static
|
|
56
|
+
static size_t MAX_BODYBUF_LENGTH = (10 * 1024 * 1024);
|
|
50
57
|
|
|
51
58
|
#if RUBY_API_VERSION_CODE >= 20700
|
|
52
59
|
# if defined rb_tainted_str_new
|
|
@@ -65,6 +72,7 @@ typedef struct lsapi_data
|
|
|
65
72
|
}lsapi_data;
|
|
66
73
|
|
|
67
74
|
static VALUE cLSAPI;
|
|
75
|
+
static VALUE eLSAPIConnectionError;
|
|
68
76
|
|
|
69
77
|
static VALUE s_req = Qnil;
|
|
70
78
|
static lsapi_data * s_req_data;
|
|
@@ -76,9 +84,10 @@ static pid_t s_pid = 0;
|
|
|
76
84
|
typedef struct lsapi_body
|
|
77
85
|
{
|
|
78
86
|
char *bodyBuf; //we put small one into memory, otherwise, into a memory mapping file, and we still use the bodyBuf to access this mapping
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
off_t bodyLen; //expected length got form content-length
|
|
88
|
+
off_t bodyCurrentLen; //current length by read() readBodyToReqBuf
|
|
89
|
+
off_t curPos;
|
|
90
|
+
int isMapped;
|
|
82
91
|
}lsapi_body;
|
|
83
92
|
|
|
84
93
|
static lsapi_body s_body;
|
|
@@ -99,7 +108,8 @@ static char sTempFile[1024] = {0};
|
|
|
99
108
|
|
|
100
109
|
static void lsapi_mark( lsapi_data * data )
|
|
101
110
|
{
|
|
102
|
-
|
|
111
|
+
if (data)
|
|
112
|
+
rb_gc_mark( data->env );
|
|
103
113
|
}
|
|
104
114
|
/*
|
|
105
115
|
* static void lsapi_free_data( lsapi_data * data )
|
|
@@ -112,20 +122,22 @@ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, in
|
|
|
112
122
|
{
|
|
113
123
|
char * p;
|
|
114
124
|
int len;
|
|
125
|
+
if (!pKey || keyLen <= 0 || !pValue || valLen < 0)
|
|
126
|
+
return 1;
|
|
115
127
|
/* Fixup some environment variables for rails */
|
|
116
128
|
switch( *pKey )
|
|
117
129
|
{
|
|
118
130
|
case 'Q':
|
|
119
|
-
if (
|
|
131
|
+
if (keyLen == 12 && memcmp(pKey, "QUERY_STRING", 12) == 0)
|
|
120
132
|
{
|
|
121
|
-
if (
|
|
133
|
+
if (valLen == 0)
|
|
122
134
|
return 1;
|
|
123
135
|
}
|
|
124
136
|
break;
|
|
125
137
|
case 'R':
|
|
126
|
-
if (
|
|
138
|
+
if (keyLen == 11 && memcmp(pKey, "REQUEST_URI", 11) == 0)
|
|
127
139
|
{
|
|
128
|
-
p =
|
|
140
|
+
p = memchr( pValue, '?', valLen );
|
|
129
141
|
if ( p )
|
|
130
142
|
{
|
|
131
143
|
len = valLen - ( p - pValue ) - 1;
|
|
@@ -143,21 +155,21 @@ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, in
|
|
|
143
155
|
rb_tainted_str_new(pValue, p - pValue));
|
|
144
156
|
rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12),
|
|
145
157
|
rb_tainted_str_new(pValue, p - pValue));
|
|
146
|
-
if (
|
|
158
|
+
if (p != pValue + valLen)
|
|
147
159
|
++p;
|
|
148
160
|
rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12),
|
|
149
161
|
rb_tainted_str_new(p, len));
|
|
150
162
|
}
|
|
151
163
|
break;
|
|
152
164
|
case 'S':
|
|
153
|
-
if (
|
|
165
|
+
if (keyLen == 11 && memcmp(pKey, "SCRIPT_NAME", 11) == 0)
|
|
154
166
|
{
|
|
155
167
|
pValue = "/";
|
|
156
168
|
valLen = 1;
|
|
157
169
|
}
|
|
158
170
|
break;
|
|
159
171
|
case 'P':
|
|
160
|
-
if (
|
|
172
|
+
if (keyLen == 9 && memcmp(pKey, "PATH_INFO", 9) == 0)
|
|
161
173
|
return 1;
|
|
162
174
|
default:
|
|
163
175
|
break;
|
|
@@ -173,6 +185,8 @@ static int add_env_rails( const char * pKey, int keyLen, const char * pValue, in
|
|
|
173
185
|
static int add_env_no_fix( const char * pKey, int keyLen, const char * pValue, int valLen,
|
|
174
186
|
void * arg )
|
|
175
187
|
{
|
|
188
|
+
if (!pKey || keyLen <= 0 || !pValue || valLen < 0)
|
|
189
|
+
return 1;
|
|
176
190
|
rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen),
|
|
177
191
|
rb_tainted_str_new(pValue, valLen));
|
|
178
192
|
return 1;
|
|
@@ -183,7 +197,7 @@ typedef int (*fn_add_env)( const char * pKey, int keyLen, const char * pValue, i
|
|
|
183
197
|
|
|
184
198
|
fn_add_env s_fn_add_env = add_env_no_fix;
|
|
185
199
|
|
|
186
|
-
static void clear_env()
|
|
200
|
+
static void clear_env(void)
|
|
187
201
|
{
|
|
188
202
|
/* rb_funcall( lsapi_env, rb_intern( "clear" ), 0 ); */
|
|
189
203
|
rb_funcall( lsapi_env, rb_intern( "replace" ), 1, env_copy );
|
|
@@ -197,21 +211,32 @@ static void setup_cgi_env( lsapi_data * data )
|
|
|
197
211
|
LSAPI_ForeachEnv_r( data->req, s_fn_add_env, data );
|
|
198
212
|
}
|
|
199
213
|
|
|
214
|
+
static void resetBodyBuf(void)
|
|
215
|
+
{
|
|
216
|
+
if (s_body.bodyBuf != NULL)
|
|
217
|
+
{
|
|
218
|
+
if (s_body.isMapped)
|
|
219
|
+
munmap(s_body.bodyBuf, (size_t)s_body.bodyLen);
|
|
220
|
+
else
|
|
221
|
+
free(s_body.bodyBuf);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
s_body.bodyBuf = NULL;
|
|
225
|
+
s_body.bodyLen = -1;
|
|
226
|
+
s_body.bodyCurrentLen = 0;
|
|
227
|
+
s_body.curPos = 0;
|
|
228
|
+
s_body.isMapped = 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
200
232
|
static VALUE lsapi_s_accept( VALUE self )
|
|
201
233
|
{
|
|
202
234
|
int pid;
|
|
235
|
+
resetBodyBuf();
|
|
203
236
|
if ( LSAPI_Prefork_Accept_r( &g_req ) == -1 )
|
|
204
237
|
return Qnil;
|
|
205
238
|
else
|
|
206
239
|
{
|
|
207
|
-
if (s_body.bodyBuf != NULL)
|
|
208
|
-
free (s_body.bodyBuf);
|
|
209
|
-
|
|
210
|
-
s_body.bodyBuf = NULL;
|
|
211
|
-
s_body.bodyLen = -1;
|
|
212
|
-
s_body.bodyCurrentLen = 0;
|
|
213
|
-
s_body.curPos = 0;
|
|
214
|
-
|
|
215
240
|
pid = getpid();
|
|
216
241
|
if ( pid != s_pid )
|
|
217
242
|
{
|
|
@@ -248,6 +273,13 @@ static VALUE lsapi_s_postfork_parent(VALUE self)
|
|
|
248
273
|
}
|
|
249
274
|
|
|
250
275
|
|
|
276
|
+
static VALUE lsapi_s_postfork_failed(VALUE self)
|
|
277
|
+
{
|
|
278
|
+
LSAPI_Postfork_Failed(&g_req);
|
|
279
|
+
return Qnil;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
251
283
|
/*
|
|
252
284
|
* static int chdir_file( const char * pFile )
|
|
253
285
|
* {
|
|
@@ -295,28 +327,77 @@ static VALUE lsapi_process( VALUE self )
|
|
|
295
327
|
}
|
|
296
328
|
|
|
297
329
|
|
|
330
|
+
//Output written while no request is active (application load, or after the
|
|
331
|
+
//last request) must not reach the LSAPI connection. m_fd alone is not
|
|
332
|
+
//enough: in connected/pipe mode it is set before any request is read.
|
|
333
|
+
//Response output is discarded, as it always has been, and stderr goes to the
|
|
334
|
+
//real fd 2. A failure during a request raises LSAPI::ConnectionError, so the
|
|
335
|
+
//runner can drop the request when the client goes away.
|
|
336
|
+
static inline int isRequestActive(lsapi_data *data)
|
|
337
|
+
{
|
|
338
|
+
return data->req->m_reqState != 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
static void raiseConnectionError(const char *message)
|
|
343
|
+
{
|
|
344
|
+
rb_raise(eLSAPIConnectionError, "%s", message);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
//write output produced outside a request; returns bytes consumed
|
|
349
|
+
static long writeInactive(lsapi_data *data, const char *pBuf, long len)
|
|
350
|
+
{
|
|
351
|
+
long done = 0;
|
|
352
|
+
ssize_t n;
|
|
353
|
+
|
|
354
|
+
if (data->fn_write == LSAPI_Write_r)
|
|
355
|
+
return len; //discarded, but consumed
|
|
356
|
+
while (done < len)
|
|
357
|
+
{
|
|
358
|
+
n = write(STDERR_FILENO, pBuf + done, (size_t)(len - done));
|
|
359
|
+
if (n > 0)
|
|
360
|
+
done += n;
|
|
361
|
+
else if (n == -1 && errno == EINTR)
|
|
362
|
+
continue;
|
|
363
|
+
else
|
|
364
|
+
rb_sys_fail("write to stderr");
|
|
365
|
+
}
|
|
366
|
+
return done;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
|
|
298
370
|
static VALUE lsapi_putc(VALUE self, VALUE c)
|
|
299
371
|
{
|
|
300
372
|
char ch = NUM2CHR(c);
|
|
301
373
|
lsapi_data *data;
|
|
302
374
|
Data_Get_Struct(self,lsapi_data, data);
|
|
375
|
+
if (!isRequestActive(data))
|
|
376
|
+
{
|
|
377
|
+
writeInactive(data, &ch, 1);
|
|
378
|
+
return c;
|
|
379
|
+
}
|
|
303
380
|
if ( (*data->fn_write)( data->req, &ch, 1 ) == 1 )
|
|
304
381
|
return c;
|
|
305
|
-
|
|
306
|
-
|
|
382
|
+
raiseConnectionError("LSAPI response write failed");
|
|
383
|
+
return Qnil;
|
|
307
384
|
}
|
|
308
385
|
|
|
309
386
|
|
|
310
387
|
static VALUE lsapi_write( VALUE self, VALUE str )
|
|
311
388
|
{
|
|
312
389
|
lsapi_data *data;
|
|
313
|
-
|
|
390
|
+
ssize_t len;
|
|
314
391
|
Data_Get_Struct(self,lsapi_data, data);
|
|
315
392
|
/* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */
|
|
316
393
|
if (TYPE(str) != T_STRING)
|
|
317
394
|
str = rb_obj_as_string(str);
|
|
395
|
+
if (!isRequestActive(data))
|
|
396
|
+
return LONG2NUM(writeInactive(data, RSTRING_PTR(str), RSTRING_LEN(str)));
|
|
318
397
|
len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) );
|
|
319
|
-
|
|
398
|
+
if (len < 0)
|
|
399
|
+
raiseConnectionError("LSAPI response write failed");
|
|
400
|
+
return LONG2NUM((long)len);
|
|
320
401
|
}
|
|
321
402
|
|
|
322
403
|
static VALUE lsapi_print( int argc, VALUE *argv, VALUE out )
|
|
@@ -433,7 +514,8 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
|
|
|
433
514
|
}
|
|
434
515
|
line = rb_obj_as_string(line);
|
|
435
516
|
lsapi_write(out, line);
|
|
436
|
-
if (
|
|
517
|
+
if (RSTRING_LEN(line) == 0 ||
|
|
518
|
+
*( RSTRING_PTR(line) + RSTRING_LEN(line) - 1 ) != '\n')
|
|
437
519
|
{
|
|
438
520
|
lsapi_write(out, rb_default_rs);
|
|
439
521
|
}
|
|
@@ -455,142 +537,195 @@ static VALUE lsapi_flush( VALUE self )
|
|
|
455
537
|
* lsapi_data *data;
|
|
456
538
|
* Data_Get_Struct(self,lsapi_data, data);
|
|
457
539
|
*/
|
|
458
|
-
|
|
540
|
+
int active = (g_req.m_reqState != 0);
|
|
541
|
+
if (LSAPI_Flush_r( &g_req ) == -1 && active)
|
|
542
|
+
raiseConnectionError("LSAPI response flush failed");
|
|
459
543
|
return Qnil;
|
|
460
544
|
}
|
|
461
545
|
|
|
462
|
-
static
|
|
546
|
+
static inline int isBodyWriteToFile(void)
|
|
463
547
|
{
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
* lsapi_data *data;
|
|
467
|
-
* Data_Get_Struct(self,lsapi_data, data);
|
|
468
|
-
*/
|
|
469
|
-
#if RUBY_API_VERSION_CODE < 20700
|
|
470
|
-
if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
|
|
471
|
-
{
|
|
472
|
-
rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
|
|
473
|
-
}
|
|
474
|
-
#endif
|
|
475
|
-
ch = LSAPI_ReqBodyGetChar_r( &g_req );
|
|
476
|
-
if ( ch == EOF )
|
|
477
|
-
return Qnil;
|
|
478
|
-
return INT2NUM( ch );
|
|
548
|
+
return s_body.bodyLen >= 0 &&
|
|
549
|
+
(uintmax_t)s_body.bodyLen >= (uintmax_t)MAX_BODYBUF_LENGTH;
|
|
479
550
|
}
|
|
480
551
|
|
|
481
|
-
static inline int isBodyWriteToFile()
|
|
482
|
-
{
|
|
483
|
-
return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0));
|
|
484
|
-
}
|
|
485
552
|
|
|
486
553
|
//create a temp file and open it, if failed, fd = -1
|
|
487
|
-
static inline int createTempFile()
|
|
554
|
+
static inline int createTempFile(void)
|
|
488
555
|
{
|
|
489
|
-
int fd
|
|
490
|
-
char
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
556
|
+
int fd;
|
|
557
|
+
char sfn[sizeof(sTempFile)];
|
|
558
|
+
|
|
559
|
+
memcpy(sfn, sTempFile, sizeof(sfn));
|
|
560
|
+
fd = mkstemp(sfn);
|
|
561
|
+
if (fd == -1)
|
|
494
562
|
fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
|
|
495
|
-
}
|
|
496
563
|
else
|
|
497
564
|
unlink(sfn);
|
|
498
|
-
|
|
499
|
-
free(sfn);
|
|
565
|
+
|
|
500
566
|
return fd;
|
|
501
567
|
}
|
|
502
568
|
|
|
503
|
-
|
|
569
|
+
|
|
570
|
+
//return 1 if error occurred
|
|
504
571
|
//if already created, always OK (0)
|
|
505
|
-
static int createBodyBuf()
|
|
572
|
+
static int createBodyBuf(void)
|
|
506
573
|
{
|
|
507
|
-
int fd
|
|
508
|
-
|
|
574
|
+
int fd;
|
|
575
|
+
off_t bodyLen;
|
|
576
|
+
|
|
577
|
+
if (s_body.bodyLen != -1)
|
|
578
|
+
return 0;
|
|
579
|
+
|
|
580
|
+
bodyLen = LSAPI_GetReqBodyLen_r(&g_req);
|
|
581
|
+
/* A missing Content-Length is valid for requests whose transport has
|
|
582
|
+
already decoded framing (for example chunked HTTP/1 or HTTP/2). The
|
|
583
|
+
LSAPI peer normally supplies the decoded length; retain the historical
|
|
584
|
+
empty-body behavior when it is genuinely unavailable. */
|
|
585
|
+
if (bodyLen < 0)
|
|
586
|
+
bodyLen = 0;
|
|
587
|
+
if ((uintmax_t)bodyLen > (uintmax_t)SIZE_MAX ||
|
|
588
|
+
(uintmax_t)bodyLen > (uintmax_t)LONG_MAX)
|
|
509
589
|
{
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
590
|
+
errno = EOVERFLOW;
|
|
591
|
+
return 1;
|
|
592
|
+
}
|
|
593
|
+
s_body.bodyLen = bodyLen;
|
|
594
|
+
|
|
595
|
+
if (bodyLen == 0)
|
|
596
|
+
return 0;
|
|
597
|
+
|
|
598
|
+
if (isBodyWriteToFile())
|
|
599
|
+
{
|
|
600
|
+
fd = createTempFile();
|
|
601
|
+
if (fd == -1)
|
|
602
|
+
return 1;
|
|
603
|
+
if (ftruncate(fd, bodyLen) != 0)
|
|
513
604
|
{
|
|
514
|
-
|
|
515
|
-
|
|
605
|
+
int saved_errno = errno;
|
|
606
|
+
close(fd);
|
|
607
|
+
errno = saved_errno;
|
|
608
|
+
return 1;
|
|
516
609
|
}
|
|
517
|
-
|
|
518
|
-
|
|
610
|
+
s_body.bodyBuf = mmap(NULL, (size_t)bodyLen, PROT_READ | PROT_WRITE,
|
|
611
|
+
MAP_SHARED, fd, 0);
|
|
612
|
+
if (s_body.bodyBuf == MAP_FAILED)
|
|
519
613
|
{
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
{
|
|
526
|
-
return 1;
|
|
527
|
-
}
|
|
528
|
-
if (ftruncate(fd, s_body.bodyLen) == 0)
|
|
529
|
-
{
|
|
530
|
-
perror("ftruncate() failed. \n");
|
|
531
|
-
close(fd);
|
|
532
|
-
return 1;
|
|
533
|
-
}
|
|
534
|
-
s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
535
|
-
if (s_body.bodyBuf == MAP_FAILED)
|
|
536
|
-
{
|
|
537
|
-
perror("File mapping failed. \n");
|
|
538
|
-
close(fd);
|
|
539
|
-
return 1;
|
|
540
|
-
}
|
|
541
|
-
close(fd); //close since needn't it anymore
|
|
542
|
-
}
|
|
543
|
-
else
|
|
544
|
-
{
|
|
545
|
-
s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char));
|
|
546
|
-
if (s_body.bodyBuf == NULL)
|
|
547
|
-
{
|
|
548
|
-
perror("Memory calloc error");
|
|
549
|
-
return 1;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
614
|
+
int saved_errno = errno;
|
|
615
|
+
s_body.bodyBuf = NULL;
|
|
616
|
+
close(fd);
|
|
617
|
+
errno = saved_errno;
|
|
618
|
+
return 1;
|
|
552
619
|
}
|
|
620
|
+
s_body.isMapped = 1;
|
|
621
|
+
close(fd);
|
|
622
|
+
}
|
|
623
|
+
else
|
|
624
|
+
{
|
|
625
|
+
s_body.bodyBuf = (char *)malloc((size_t)bodyLen);
|
|
626
|
+
if (s_body.bodyBuf == NULL)
|
|
627
|
+
return 1;
|
|
553
628
|
}
|
|
554
629
|
|
|
555
|
-
return 0;
|
|
630
|
+
return 0;
|
|
556
631
|
}
|
|
557
632
|
|
|
558
|
-
|
|
633
|
+
|
|
634
|
+
static void raiseBodyError(const char *message)
|
|
559
635
|
{
|
|
560
|
-
|
|
636
|
+
int saved_errno = errno;
|
|
637
|
+
resetBodyBuf();
|
|
638
|
+
errno = saved_errno ? saved_errno : EIO;
|
|
639
|
+
rb_sys_fail(message);
|
|
561
640
|
}
|
|
562
641
|
|
|
563
|
-
|
|
642
|
+
|
|
643
|
+
static inline int isAllBodyRead(void)
|
|
564
644
|
{
|
|
565
|
-
return
|
|
645
|
+
return s_body.bodyCurrentLen >= s_body.bodyLen;
|
|
566
646
|
}
|
|
567
|
-
|
|
568
|
-
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
static inline int isEofBodyBuf(void)
|
|
569
650
|
{
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
651
|
+
return s_body.bodyLen >= 0 && s_body.curPos >= s_body.bodyLen;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
//try to read length as multiples of 8KB
|
|
656
|
+
static ssize_t readBodyBuf(off_t needRead)
|
|
657
|
+
{
|
|
658
|
+
const off_t blockSize = 8192;
|
|
659
|
+
off_t available = s_body.bodyLen - s_body.bodyCurrentLen;
|
|
660
|
+
off_t readMore;
|
|
661
|
+
off_t remain;
|
|
662
|
+
ssize_t nRead;
|
|
578
663
|
|
|
579
|
-
if (
|
|
664
|
+
if (available <= 0)
|
|
580
665
|
return 0;
|
|
581
|
-
|
|
582
|
-
nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore);
|
|
583
|
-
if ( nRead > 0 )
|
|
584
|
-
s_body.bodyCurrentLen += nRead;
|
|
585
666
|
|
|
667
|
+
readMore = needRead;
|
|
668
|
+
if (readMore < blockSize)
|
|
669
|
+
readMore = blockSize;
|
|
670
|
+
else if (readMore % blockSize != 0 &&
|
|
671
|
+
readMore <= available - (blockSize - readMore % blockSize))
|
|
672
|
+
readMore += blockSize - readMore % blockSize;
|
|
673
|
+
if (readMore > available)
|
|
674
|
+
readMore = available;
|
|
675
|
+
|
|
676
|
+
remain = LSAPI_GetReqBodyRemain_r(&g_req);
|
|
677
|
+
if (remain <= 0)
|
|
678
|
+
{
|
|
679
|
+
errno = EIO;
|
|
680
|
+
return -1;
|
|
681
|
+
}
|
|
682
|
+
if (readMore > remain)
|
|
683
|
+
readMore = remain;
|
|
684
|
+
if ((uintmax_t)readMore > (uintmax_t)SSIZE_MAX)
|
|
685
|
+
readMore = SSIZE_MAX;
|
|
686
|
+
|
|
687
|
+
nRead = LSAPI_ReadReqBody_r(&g_req,
|
|
688
|
+
s_body.bodyBuf + (size_t)s_body.bodyCurrentLen,
|
|
689
|
+
(size_t)readMore);
|
|
690
|
+
if (nRead > 0)
|
|
691
|
+
s_body.bodyCurrentLen += nRead;
|
|
692
|
+
else
|
|
693
|
+
{
|
|
694
|
+
if (errno == 0)
|
|
695
|
+
errno = EIO;
|
|
696
|
+
return -1;
|
|
697
|
+
}
|
|
586
698
|
return nRead;
|
|
587
699
|
}
|
|
588
700
|
|
|
701
|
+
|
|
702
|
+
static VALUE lsapi_getc( VALUE self )
|
|
703
|
+
{
|
|
704
|
+
unsigned char ch;
|
|
705
|
+
#if RUBY_API_VERSION_CODE < 20700
|
|
706
|
+
if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
|
|
707
|
+
{
|
|
708
|
+
rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
|
|
709
|
+
}
|
|
710
|
+
#endif
|
|
711
|
+
if (createBodyBuf() != 0)
|
|
712
|
+
raiseBodyError("cannot allocate LSAPI request body buffer");
|
|
713
|
+
if (isEofBodyBuf())
|
|
714
|
+
return Qnil;
|
|
715
|
+
while (s_body.bodyCurrentLen <= s_body.curPos)
|
|
716
|
+
{
|
|
717
|
+
if (readBodyBuf(1) <= 0)
|
|
718
|
+
raiseBodyError("cannot read LSAPI request body");
|
|
719
|
+
}
|
|
720
|
+
ch = (unsigned char)s_body.bodyBuf[(size_t)s_body.curPos++];
|
|
721
|
+
return INT2NUM( ch );
|
|
722
|
+
}
|
|
723
|
+
|
|
589
724
|
static VALUE lsapi_gets( VALUE self )
|
|
590
725
|
{
|
|
591
726
|
VALUE str;
|
|
592
727
|
const int blkSize = 4096;
|
|
593
|
-
|
|
728
|
+
off_t n;
|
|
594
729
|
char *p = NULL;
|
|
595
730
|
|
|
596
731
|
#if RUBY_API_VERSION_CODE < 20700
|
|
@@ -599,34 +734,37 @@ static VALUE lsapi_gets( VALUE self )
|
|
|
599
734
|
rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
|
|
600
735
|
}
|
|
601
736
|
#endif
|
|
602
|
-
if (createBodyBuf()
|
|
603
|
-
|
|
737
|
+
if (createBodyBuf() != 0)
|
|
738
|
+
raiseBodyError("cannot allocate LSAPI request body buffer");
|
|
739
|
+
if (isEofBodyBuf())
|
|
604
740
|
return Qnil;
|
|
605
|
-
}
|
|
606
741
|
|
|
607
742
|
//comment:
|
|
608
|
-
while((
|
|
743
|
+
while(memchr(s_body.bodyBuf + (size_t)s_body.curPos, '\n',
|
|
744
|
+
(size_t)(s_body.bodyCurrentLen - s_body.curPos)) == NULL)
|
|
609
745
|
{
|
|
610
746
|
if (isAllBodyRead() == 1)
|
|
611
747
|
break;
|
|
612
748
|
//read one page and check, then reply
|
|
613
|
-
readBodyBuf(blkSize)
|
|
749
|
+
if (readBodyBuf(blkSize) <= 0)
|
|
750
|
+
raiseBodyError("cannot read LSAPI request body");
|
|
614
751
|
}
|
|
615
752
|
|
|
616
|
-
p =
|
|
753
|
+
p = memchr(s_body.bodyBuf + (size_t)s_body.curPos, '\n',
|
|
754
|
+
(size_t)(s_body.bodyCurrentLen - s_body.curPos));
|
|
617
755
|
if (p != NULL)
|
|
618
756
|
n = p - s_body.bodyBuf - s_body.curPos + 1;
|
|
619
757
|
else
|
|
620
758
|
n = s_body.bodyCurrentLen - s_body.curPos;
|
|
621
759
|
|
|
622
|
-
str = rb_str_buf_new(
|
|
760
|
+
str = rb_str_buf_new((long)n);
|
|
623
761
|
#if RUBY_API_VERSION_CODE < 20700
|
|
624
762
|
OBJ_TAINT(str);
|
|
625
763
|
#endif
|
|
626
764
|
|
|
627
765
|
if (n > 0)
|
|
628
766
|
{
|
|
629
|
-
rb_str_buf_cat(
|
|
767
|
+
rb_str_buf_cat(str, s_body.bodyBuf + (size_t)s_body.curPos, (long)n);
|
|
630
768
|
s_body.curPos += n;
|
|
631
769
|
}
|
|
632
770
|
|
|
@@ -636,9 +774,11 @@ static VALUE lsapi_gets( VALUE self )
|
|
|
636
774
|
static VALUE lsapi_read(int argc, VALUE *argv, VALUE self)
|
|
637
775
|
{
|
|
638
776
|
VALUE str;
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
777
|
+
VALUE length = Qnil;
|
|
778
|
+
VALUE outbuf = Qnil;
|
|
779
|
+
off_t n;
|
|
780
|
+
off_t target;
|
|
781
|
+
int length_given;
|
|
642
782
|
|
|
643
783
|
#if RUBY_API_VERSION_CODE < 20700
|
|
644
784
|
if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
|
|
@@ -646,54 +786,52 @@ static VALUE lsapi_read(int argc, VALUE *argv, VALUE self)
|
|
|
646
786
|
rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
|
|
647
787
|
}
|
|
648
788
|
#endif
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
789
|
+
rb_scan_args(argc, argv, "02", &length, &outbuf);
|
|
790
|
+
if (createBodyBuf() != 0)
|
|
791
|
+
raiseBodyError("cannot allocate LSAPI request body buffer");
|
|
653
792
|
|
|
654
793
|
//we need to consider these 4 cases:
|
|
655
794
|
//1, need all data since argc == 0, we may have all data 2, or not
|
|
656
795
|
//3, need a length of data (argv >= 1), we may have enough data already read, 4, or not
|
|
657
|
-
|
|
796
|
+
length_given = argc > 0 && !NIL_P(length);
|
|
797
|
+
if (!length_given)
|
|
658
798
|
n = s_body.bodyLen - s_body.curPos;
|
|
659
799
|
else
|
|
660
800
|
{
|
|
661
|
-
|
|
801
|
+
long requested = NUM2LONG(length);
|
|
802
|
+
n = (off_t)requested;
|
|
662
803
|
if (n < 0)
|
|
663
|
-
|
|
804
|
+
rb_raise(rb_eArgError, "negative length %ld given", requested);
|
|
664
805
|
if (n > s_body.bodyLen - s_body.curPos)
|
|
665
|
-
n = s_body.bodyLen - s_body.curPos;
|
|
806
|
+
n = s_body.bodyLen - s_body.curPos;
|
|
666
807
|
}
|
|
667
|
-
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
808
|
+
|
|
809
|
+
if (!NIL_P(outbuf))
|
|
810
|
+
{
|
|
811
|
+
StringValue(outbuf);
|
|
812
|
+
rb_str_resize(outbuf, 0);
|
|
813
|
+
str = outbuf;
|
|
814
|
+
}
|
|
815
|
+
else
|
|
816
|
+
str = rb_str_buf_new((long)n);
|
|
672
817
|
#if RUBY_API_VERSION_CODE < 20700
|
|
673
818
|
OBJ_TAINT(str);
|
|
674
819
|
#endif
|
|
675
820
|
if (n == 0)
|
|
676
|
-
return str;
|
|
677
|
-
|
|
678
|
-
//copy already have part first
|
|
679
|
-
if (n - needRead != 0)
|
|
680
821
|
{
|
|
681
|
-
|
|
682
|
-
|
|
822
|
+
if (length_given && NUM2LONG(length) != 0)
|
|
823
|
+
return Qnil;
|
|
824
|
+
return str;
|
|
683
825
|
}
|
|
684
|
-
|
|
685
|
-
|
|
826
|
+
|
|
827
|
+
target = s_body.curPos + n;
|
|
828
|
+
while (s_body.bodyCurrentLen < target)
|
|
686
829
|
{
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if (nRead > 0)
|
|
690
|
-
{
|
|
691
|
-
n = ((nRead < needRead) ? nRead : needRead);
|
|
692
|
-
rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n );
|
|
693
|
-
s_body.curPos += n;
|
|
694
|
-
}
|
|
830
|
+
if (readBodyBuf(target - s_body.bodyCurrentLen) <= 0)
|
|
831
|
+
raiseBodyError("cannot read LSAPI request body");
|
|
695
832
|
}
|
|
696
|
-
|
|
833
|
+
rb_str_buf_cat(str, s_body.bodyBuf + (size_t)s_body.curPos, (long)n);
|
|
834
|
+
s_body.curPos += n;
|
|
697
835
|
return str;
|
|
698
836
|
}
|
|
699
837
|
|
|
@@ -711,6 +849,8 @@ static VALUE lsapi_each(VALUE self)
|
|
|
711
849
|
while(isEofBodyBuf() != 1)
|
|
712
850
|
{
|
|
713
851
|
str = lsapi_gets(self);
|
|
852
|
+
if (NIL_P(str))
|
|
853
|
+
break;
|
|
714
854
|
rb_yield(str);
|
|
715
855
|
}
|
|
716
856
|
return self;
|
|
@@ -719,7 +859,9 @@ static VALUE lsapi_each(VALUE self)
|
|
|
719
859
|
|
|
720
860
|
static VALUE lsapi_eof(VALUE self)
|
|
721
861
|
{
|
|
722
|
-
|
|
862
|
+
if (createBodyBuf() != 0)
|
|
863
|
+
raiseBodyError("cannot allocate LSAPI request body buffer");
|
|
864
|
+
return isEofBodyBuf() ? Qtrue : Qfalse;
|
|
723
865
|
}
|
|
724
866
|
|
|
725
867
|
static VALUE lsapi_binmode(VALUE self)
|
|
@@ -732,6 +874,11 @@ static VALUE lsapi_isatty(VALUE self)
|
|
|
732
874
|
return Qfalse;
|
|
733
875
|
}
|
|
734
876
|
|
|
877
|
+
static VALUE lsapi_isclosed(VALUE self)
|
|
878
|
+
{
|
|
879
|
+
return Qfalse;
|
|
880
|
+
}
|
|
881
|
+
|
|
735
882
|
static VALUE lsapi_sync(VALUE self)
|
|
736
883
|
{
|
|
737
884
|
return Qfalse;
|
|
@@ -744,21 +891,11 @@ static VALUE lsapi_setsync(VALUE self,VALUE sync)
|
|
|
744
891
|
|
|
745
892
|
static VALUE lsapi_close(VALUE self)
|
|
746
893
|
{
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
munmap(s_body.bodyBuf, s_body.bodyLen);
|
|
753
|
-
}
|
|
754
|
-
else
|
|
755
|
-
free(s_body.bodyBuf);
|
|
756
|
-
|
|
757
|
-
s_body.bodyBuf = NULL;
|
|
758
|
-
s_body.bodyLen = -1;
|
|
759
|
-
s_body.bodyCurrentLen = 0;
|
|
760
|
-
s_body.curPos = 0;
|
|
761
|
-
//Should the temp be deleted here?!
|
|
894
|
+
int active = (g_req.m_reqState != 0);
|
|
895
|
+
int flushResult = LSAPI_Flush_r( &g_req );
|
|
896
|
+
resetBodyBuf();
|
|
897
|
+
if (flushResult == -1 && active)
|
|
898
|
+
raiseConnectionError("LSAPI response flush failed");
|
|
762
899
|
|
|
763
900
|
return Qnil;
|
|
764
901
|
}
|
|
@@ -783,49 +920,83 @@ static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self)
|
|
|
783
920
|
return self;
|
|
784
921
|
}
|
|
785
922
|
|
|
786
|
-
static void readMaxBodyBufLength()
|
|
923
|
+
static void readMaxBodyBufLength(void)
|
|
787
924
|
{
|
|
788
|
-
|
|
925
|
+
uintmax_t n;
|
|
926
|
+
uintmax_t multiplier = 1;
|
|
927
|
+
char *end;
|
|
789
928
|
const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" );
|
|
790
|
-
if (
|
|
929
|
+
if (p)
|
|
791
930
|
{
|
|
792
|
-
n
|
|
793
|
-
|
|
931
|
+
//accepts "<n>", "<n>K", "<n>M", with optional spaces and "B" suffix
|
|
932
|
+
while (*p == ' ')
|
|
933
|
+
++p;
|
|
934
|
+
if (!isdigit((unsigned char)*p))
|
|
935
|
+
return;
|
|
936
|
+
errno = 0;
|
|
937
|
+
n = strtoumax(p, &end, 10);
|
|
938
|
+
while (*end == ' ')
|
|
939
|
+
++end;
|
|
940
|
+
if (*end == 'M' || *end == 'm')
|
|
941
|
+
multiplier = 1024 * 1024;
|
|
942
|
+
else if (*end == 'K' || *end == 'k')
|
|
943
|
+
multiplier = 1024;
|
|
944
|
+
if (multiplier != 1)
|
|
794
945
|
{
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
MAX_BODYBUF_LENGTH = n * 1024;
|
|
799
|
-
else
|
|
800
|
-
MAX_BODYBUF_LENGTH = n;
|
|
946
|
+
++end;
|
|
947
|
+
if (*end == 'B' || *end == 'b')
|
|
948
|
+
++end;
|
|
801
949
|
}
|
|
950
|
+
while (*end == ' ')
|
|
951
|
+
++end;
|
|
952
|
+
if (errno == 0 && n > 0 && *end == '\0' &&
|
|
953
|
+
n <= (uintmax_t)SIZE_MAX / multiplier)
|
|
954
|
+
MAX_BODYBUF_LENGTH = (size_t)(n * multiplier);
|
|
802
955
|
}
|
|
803
956
|
}
|
|
804
957
|
|
|
805
|
-
static void readTempFileTemplate()
|
|
958
|
+
static void readTempFileTemplate(void)
|
|
806
959
|
{
|
|
807
960
|
const char *p = getenv( "LSAPI_TEMPFILE" );
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
961
|
+
size_t len;
|
|
962
|
+
|
|
963
|
+
if (p == NULL || *p == '\0')
|
|
964
|
+
p = "/tmp/lsapi.XXXXXX";
|
|
965
|
+
len = strlen(p);
|
|
966
|
+
if (len >= sizeof(sTempFile) ||
|
|
967
|
+
(len > sizeof(sTempFile) - sizeof(".XXXXXX") &&
|
|
968
|
+
(len < 6 || memcmp(p + len - 6, "XXXXXX", 6) != 0)))
|
|
969
|
+
{
|
|
970
|
+
p = "/tmp/lsapi.XXXXXX";
|
|
971
|
+
len = strlen(p);
|
|
972
|
+
}
|
|
973
|
+
if (len < 6 || memcmp(p + len - 6, "XXXXXX", 6) != 0)
|
|
974
|
+
{
|
|
975
|
+
snprintf(sTempFile, sizeof(sTempFile), "%s.XXXXXX", p);
|
|
976
|
+
}
|
|
977
|
+
else
|
|
978
|
+
{
|
|
979
|
+
snprintf(sTempFile, sizeof(sTempFile), "%s", p);
|
|
980
|
+
}
|
|
814
981
|
}
|
|
815
982
|
|
|
816
|
-
static void initBodyBuf()
|
|
983
|
+
static void initBodyBuf(void)
|
|
817
984
|
{
|
|
818
985
|
s_body.bodyBuf = NULL;
|
|
819
986
|
s_body.bodyLen = -1;
|
|
820
987
|
s_body.bodyCurrentLen = 0;
|
|
821
988
|
s_body.curPos = 0;
|
|
989
|
+
s_body.isMapped = 0;
|
|
822
990
|
}
|
|
823
|
-
void Init_lsapi()
|
|
991
|
+
void Init_lsapi(void)
|
|
824
992
|
{
|
|
825
993
|
VALUE orig_verbose;
|
|
826
994
|
char * p;
|
|
827
995
|
int prefork = 0;
|
|
828
|
-
|
|
996
|
+
if (geteuid() == 0)
|
|
997
|
+
rb_raise(rb_eSecurityError, "ruby-lsapi refuses to run as root");
|
|
998
|
+
if (LSAPI_Init() == -1)
|
|
999
|
+
rb_raise(rb_eRuntimeError, "failed to initialize LSAPI");
|
|
829
1000
|
initBodyBuf();
|
|
830
1001
|
|
|
831
1002
|
readMaxBodyBufLength();
|
|
@@ -836,9 +1007,11 @@ void Init_lsapi()
|
|
|
836
1007
|
prefork = 1;
|
|
837
1008
|
|
|
838
1009
|
#ifdef rb_thread_select
|
|
839
|
-
LSAPI_Init_Env_Parameters( rb_thread_select )
|
|
1010
|
+
if (LSAPI_Init_Env_Parameters( rb_thread_select ) == -1)
|
|
1011
|
+
rb_raise(rb_eRuntimeError, "failed to initialize LSAPI environment");
|
|
840
1012
|
#else
|
|
841
|
-
LSAPI_Init_Env_Parameters( select )
|
|
1013
|
+
if (LSAPI_Init_Env_Parameters( select ) == -1)
|
|
1014
|
+
rb_raise(rb_eRuntimeError, "failed to initialize LSAPI environment");
|
|
842
1015
|
#endif
|
|
843
1016
|
|
|
844
1017
|
s_pid = getpid();
|
|
@@ -847,7 +1020,7 @@ void Init_lsapi()
|
|
|
847
1020
|
if ( p )
|
|
848
1021
|
{
|
|
849
1022
|
if ( chdir( p ) == -1 )
|
|
850
|
-
|
|
1023
|
+
rb_sys_fail( "cannot chdir to RACK_ROOT" );
|
|
851
1024
|
}
|
|
852
1025
|
if ( p || getenv( "RACK_ENV" ) )
|
|
853
1026
|
s_fn_add_env = add_env_rails;
|
|
@@ -863,19 +1036,32 @@ void Init_lsapi()
|
|
|
863
1036
|
|
|
864
1037
|
/* tell the garbage collector it is a global variable, do not recycle it. */
|
|
865
1038
|
rb_global_variable(&env_copy);
|
|
1039
|
+
/* $stdin/$stdout/$stderr, STDERR and ENV are replaced below; keep the
|
|
1040
|
+
original objects alive. Ruby <= 2.0 only references its own STDERR
|
|
1041
|
+
through those, yet still writes errors to it when a process exits. */
|
|
1042
|
+
rb_global_variable(&orig_stdin);
|
|
1043
|
+
rb_global_variable(&orig_stdout);
|
|
1044
|
+
rb_global_variable(&orig_stderr);
|
|
1045
|
+
rb_global_variable(&orig_env);
|
|
866
1046
|
|
|
867
|
-
rb_hash_aset( env_copy,rb_tainted_str_new("
|
|
1047
|
+
rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_INTERFACE", 17),
|
|
868
1048
|
rb_tainted_str_new("CGI/1.2", 7));
|
|
869
1049
|
|
|
870
1050
|
rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1);
|
|
871
1051
|
|
|
872
1052
|
cLSAPI = rb_define_class("LSAPI", rb_cObject);
|
|
1053
|
+
/* instances only come from Data_Make_Struct() below */
|
|
1054
|
+
rb_undef_alloc_func(cLSAPI);
|
|
1055
|
+
/* raised when writing the response fails because the client is gone */
|
|
1056
|
+
eLSAPIConnectionError = rb_define_class_under(cLSAPI, "ConnectionError", rb_eIOError);
|
|
873
1057
|
rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0);
|
|
874
|
-
|
|
1058
|
+
/* the prefork server only exists when listening on a socket */
|
|
1059
|
+
if (prefork && LSAPI_Is_Listen())
|
|
875
1060
|
{
|
|
876
1061
|
rb_define_singleton_method(cLSAPI, "accept_new_connection", lsapi_s_accept_new_conn, 0);
|
|
877
1062
|
rb_define_singleton_method(cLSAPI, "postfork_child", lsapi_s_postfork_child, 0);
|
|
878
1063
|
rb_define_singleton_method(cLSAPI, "postfork_parent", lsapi_s_postfork_parent, 0);
|
|
1064
|
+
rb_define_singleton_method(cLSAPI, "postfork_failed", lsapi_s_postfork_failed, 0);
|
|
879
1065
|
}
|
|
880
1066
|
|
|
881
1067
|
rb_define_method(cLSAPI, "process", lsapi_process, 0 );
|
|
@@ -901,7 +1087,7 @@ void Init_lsapi()
|
|
|
901
1087
|
rb_define_method(cLSAPI, "eof", lsapi_eof, 0);
|
|
902
1088
|
rb_define_method(cLSAPI, "eof?", lsapi_eof, 0);
|
|
903
1089
|
rb_define_method(cLSAPI, "close", lsapi_close, 0);
|
|
904
|
-
|
|
1090
|
+
rb_define_method(cLSAPI, "closed?", lsapi_isclosed, 0);
|
|
905
1091
|
rb_define_method(cLSAPI, "binmode", lsapi_binmode, 0);
|
|
906
1092
|
rb_define_method(cLSAPI, "isatty", lsapi_isatty, 0);
|
|
907
1093
|
rb_define_method(cLSAPI, "tty?", lsapi_isatty, 0);
|
|
@@ -912,6 +1098,7 @@ void Init_lsapi()
|
|
|
912
1098
|
|
|
913
1099
|
s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data );
|
|
914
1100
|
s_req_data->req = &g_req;
|
|
1101
|
+
s_req_data->env = Qnil;
|
|
915
1102
|
s_req_data->fn_write = LSAPI_Write_r;
|
|
916
1103
|
rb_stdin = rb_stdout = s_req;
|
|
917
1104
|
|
|
@@ -923,6 +1110,7 @@ void Init_lsapi()
|
|
|
923
1110
|
|
|
924
1111
|
s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data );
|
|
925
1112
|
s_stderr_data->req = &g_req;
|
|
1113
|
+
s_stderr_data->env = Qnil;
|
|
926
1114
|
s_stderr_data->fn_write = LSAPI_Write_Stderr_r;
|
|
927
1115
|
rb_stderr = s_req_stderr;
|
|
928
1116
|
rb_global_variable(&s_req_stderr );
|
|
@@ -932,6 +1120,8 @@ void Init_lsapi()
|
|
|
932
1120
|
ruby_verbose = Qnil;
|
|
933
1121
|
|
|
934
1122
|
lsapi_env = rb_hash_new();
|
|
1123
|
+
s_req_data->env = lsapi_env;
|
|
1124
|
+
s_stderr_data->env = lsapi_env;
|
|
935
1125
|
clear_env();
|
|
936
1126
|
/* redefine ENV using a hash table, should be faster than char **environment */
|
|
937
1127
|
rb_define_global_const("ENV", lsapi_env);
|
|
@@ -942,4 +1132,3 @@ void Init_lsapi()
|
|
|
942
1132
|
|
|
943
1133
|
return;
|
|
944
1134
|
}
|
|
945
|
-
|