ruby-lsapi 4.2 → 4.3

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.
@@ -38,9 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
38
  extern "C" {
39
39
  #endif
40
40
 
41
- #include <stddef.h>
42
- #include <lsapidef.h>
41
+ #include "lsapidef.h"
43
42
 
43
+ #include <stddef.h>
44
44
  #include <sys/time.h>
45
45
  #include <sys/types.h>
46
46
 
@@ -276,28 +276,28 @@ static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg )
276
276
  static inline char * LSAPI_GetEnv( const char * name )
277
277
  { return LSAPI_GetEnv_r( &g_req, name ); }
278
278
 
279
- static inline char * LSAPI_GetQueryString()
279
+ static inline char * LSAPI_GetQueryString(void)
280
280
  { return LSAPI_GetQueryString_r( &g_req ); }
281
281
 
282
- static inline char * LSAPI_GetScriptFileName()
282
+ static inline char * LSAPI_GetScriptFileName(void)
283
283
  { return LSAPI_GetScriptFileName_r( &g_req ); }
284
284
 
285
- static inline char * LSAPI_GetScriptName()
285
+ static inline char * LSAPI_GetScriptName(void)
286
286
  { return LSAPI_GetScriptName_r( &g_req ); }
287
287
 
288
- static inline char * LSAPI_GetRequestMethod()
288
+ static inline char * LSAPI_GetRequestMethod(void)
289
289
  { return LSAPI_GetRequestMethod_r( &g_req ); }
290
290
 
291
- static inline off_t LSAPI_GetReqBodyLen()
291
+ static inline off_t LSAPI_GetReqBodyLen(void)
292
292
  { return LSAPI_GetReqBodyLen_r( &g_req ); }
293
293
 
294
- static inline off_t LSAPI_GetReqBodyRemain()
294
+ static inline off_t LSAPI_GetReqBodyRemain(void)
295
295
  { return LSAPI_GetReqBodyRemain_r( &g_req ); }
296
296
 
297
297
  static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len )
298
298
  { return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); }
299
299
 
300
- static inline int LSAPI_ReqBodyGetChar()
300
+ static inline int LSAPI_ReqBodyGetChar(void)
301
301
  { return LSAPI_ReqBodyGetChar_r( &g_req ); }
302
302
 
303
303
  static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF )
@@ -319,7 +319,7 @@ static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size )
319
319
  static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len )
320
320
  { return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); }
321
321
 
322
- static inline int LSAPI_Flush()
322
+ static inline int LSAPI_Flush(void)
323
323
  { return LSAPI_Flush_r( &g_req ); }
324
324
 
325
325
  static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
@@ -359,9 +359,9 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp );
359
359
 
360
360
  void LSAPI_Set_Slow_Req_Msecs( int msecs );
361
361
 
362
- int LSAPI_Get_Slow_Req_Msecs( );
362
+ int LSAPI_Get_Slow_Req_Msecs(void);
363
363
 
364
- int LSAPI_is_suEXEC_Daemon();
364
+ int LSAPI_is_suEXEC_Daemon(void);
365
365
 
366
366
  #if defined (c_plusplus) || defined (__cplusplus)
367
367
  }
@@ -15,6 +15,8 @@
15
15
  #include <sys/socket.h>
16
16
  #include <sys/wait.h>
17
17
  #include <unistd.h>
18
+ #include <sys/mman.h>
19
+ #include <fcntl.h>
18
20
 
19
21
  /* RUBY_EXTERN VALUE ruby_errinfo; */
20
22
  RUBY_EXTERN VALUE rb_stdin;
@@ -36,6 +38,7 @@ static VALUE env_copy;
36
38
 
37
39
  static VALUE lsapi_env;
38
40
 
41
+ static int MAX_BODYBUF_LENGTH = (10 * 1024 * 1024);
39
42
 
40
43
  /* static VALUE lsapi_objrefs; */
41
44
 
@@ -44,10 +47,8 @@ typedef struct lsapi_data
44
47
  LSAPI_Request * req;
45
48
  VALUE env;
46
49
  ssize_t (* fn_write)( LSAPI_Request *, const char * , size_t );
47
-
48
50
  }lsapi_data;
49
51
 
50
-
51
52
  static VALUE cLSAPI;
52
53
 
53
54
  static VALUE s_req = Qnil;
@@ -57,17 +58,28 @@ static VALUE s_req_stderr = Qnil;
57
58
  static lsapi_data * s_stderr_data;
58
59
  static pid_t s_pid = 0;
59
60
 
60
- /*
61
- static void lsapi_ruby_setenv(const char *name, const char *value)
61
+ typedef struct lsapi_body
62
62
  {
63
- if (!name) return;
63
+ char *bodyBuf; //we put small one into memory, otherwise, into a memory mapping file, and we still use the bodyBuf to access this mapping
64
+ int bodyLen; //expected length got form content-length
65
+ int bodyCurrentLen; //current length by read() readBodyToReqBuf
66
+ int curPos;
67
+ }lsapi_body;
64
68
 
65
- if (value && *value)
66
- ruby_setenv(name, value);
67
- else
68
- ruby_unsetenv(name);
69
- }
70
- */
69
+ static lsapi_body s_body;
70
+ static char sTempFile[1024] = {0};
71
+
72
+ /*
73
+ * static void lsapi_ruby_setenv(const char *name, const char *value)
74
+ * {
75
+ * if (!name) return;
76
+ *
77
+ * if (value && *value)
78
+ * ruby_setenv(name, value);
79
+ * else
80
+ * ruby_unsetenv(name);
81
+ } * *
82
+ */
71
83
 
72
84
 
73
85
  static void lsapi_mark( lsapi_data * data )
@@ -75,87 +87,87 @@ static void lsapi_mark( lsapi_data * data )
75
87
  rb_gc_mark( data->env );
76
88
  }
77
89
  /*
78
- static void lsapi_free_data( lsapi_data * data )
79
- {
80
- free( data );
81
- }
82
- */
90
+ * static void lsapi_free_data( lsapi_data * data )
91
+ * {
92
+ * free( data );
93
+ } * *
94
+ */
83
95
  static int add_env_rails( const char * pKey, int keyLen, const char * pValue, int valLen,
84
- void * arg )
96
+ void * arg )
85
97
  {
86
98
  char * p;
87
99
  int len;
88
100
  /* Fixup some environment variables for rails */
89
101
  switch( *pKey )
90
102
  {
91
- case 'Q':
92
- if ( strcmp( pKey, "QUERY_STRING" ) == 0 )
93
- {
94
- if ( !*pValue )
95
- return 1;
96
- }
97
- break;
98
- case 'R':
99
- if (( *(pKey+8) == 'U' )&&( strcmp( pKey, "REQUEST_URI" ) == 0 ))
100
- {
101
- p = strchr( pValue, '?' );
102
- if ( p )
103
+ case 'Q':
104
+ if ( strcmp( pKey, "QUERY_STRING" ) == 0 )
103
105
  {
104
- len = valLen - ( p - pValue ) - 1;
105
- /*
106
- valLen = p - pValue;
107
- *p++ = 0;
108
- */
106
+ if ( !*pValue )
107
+ return 1;
109
108
  }
110
- else
109
+ break;
110
+ case 'R':
111
+ if (( *(pKey+8) == 'U' )&&( strcmp( pKey, "REQUEST_URI" ) == 0 ))
111
112
  {
112
- p = (char *)pValue + valLen;
113
- len = 0;
113
+ p = strchr( pValue, '?' );
114
+ if ( p )
115
+ {
116
+ len = valLen - ( p - pValue ) - 1;
117
+ /*
118
+ * valLen = p - pValue;
119
+ *p++ = 0;
120
+ */
121
+ }
122
+ else
123
+ {
124
+ p = (char *)pValue + valLen;
125
+ len = 0;
126
+ }
127
+ rb_hash_aset( lsapi_env,rb_tainted_str_new("PATH_INFO", 9),
128
+ rb_tainted_str_new(pValue, p - pValue));
129
+ rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12),
130
+ rb_tainted_str_new(pValue, p - pValue));
131
+ if ( *p == '?' )
132
+ ++p;
133
+ rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12),
134
+ rb_tainted_str_new(p, len));
114
135
  }
115
- rb_hash_aset( lsapi_env,rb_tainted_str_new("PATH_INFO", 9),
116
- rb_tainted_str_new(pValue, p - pValue));
117
- rb_hash_aset( lsapi_env,rb_tainted_str_new("REQUEST_PATH", 12),
118
- rb_tainted_str_new(pValue, p - pValue));
119
- if ( *p == '?' )
120
- ++p;
121
- rb_hash_aset( lsapi_env,rb_tainted_str_new("QUERY_STRING", 12),
122
- rb_tainted_str_new(p, len));
123
- }
124
- break;
125
- case 'S':
126
- if ( strcmp( pKey, "SCRIPT_NAME" ) == 0 )
127
- {
128
- pValue = "/";
129
- valLen = 1;
130
- }
131
- break;
132
- case 'P':
133
- if ( strcmp( pKey, "PATH_INFO" ) == 0 )
134
- return 1;
135
- default:
136
- break;
136
+ break;
137
+ case 'S':
138
+ if ( strcmp( pKey, "SCRIPT_NAME" ) == 0 )
139
+ {
140
+ pValue = "/";
141
+ valLen = 1;
142
+ }
143
+ break;
144
+ case 'P':
145
+ if ( strcmp( pKey, "PATH_INFO" ) == 0 )
146
+ return 1;
147
+ default:
148
+ break;
137
149
  }
138
150
 
139
151
  /* lsapi_ruby_setenv(pKey, pValue ); */
140
152
 
141
153
  rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen),
142
- rb_tainted_str_new(pValue, valLen));
154
+ rb_tainted_str_new(pValue, valLen));
143
155
  return 1;
144
156
  }
145
157
 
146
158
  static int add_env_no_fix( const char * pKey, int keyLen, const char * pValue, int valLen,
147
- void * arg )
159
+ void * arg )
148
160
  {
149
161
  rb_hash_aset( lsapi_env,rb_tainted_str_new(pKey, keyLen),
150
- rb_tainted_str_new(pValue, valLen));
162
+ rb_tainted_str_new(pValue, valLen));
151
163
  return 1;
152
164
  }
153
165
 
154
166
  typedef int (*fn_add_env)( const char * pKey, int keyLen, const char * pValue, int valLen,
155
- void * arg );
156
-
167
+ void * arg );
168
+
157
169
  fn_add_env s_fn_add_env = add_env_no_fix;
158
-
170
+
159
171
  static void clear_env()
160
172
  {
161
173
  /* rb_funcall( lsapi_env, rb_intern( "clear" ), 0 ); */
@@ -165,15 +177,11 @@ static void clear_env()
165
177
  static void setup_cgi_env( lsapi_data * data )
166
178
  {
167
179
  clear_env();
168
-
180
+
169
181
  LSAPI_ForeachHeader_r( data->req, s_fn_add_env, data );
170
182
  LSAPI_ForeachEnv_r( data->req, s_fn_add_env, data );
171
-
172
183
  }
173
184
 
174
-
175
-
176
-
177
185
  static VALUE lsapi_s_accept( VALUE self )
178
186
  {
179
187
  int pid;
@@ -181,33 +189,39 @@ static VALUE lsapi_s_accept( VALUE self )
181
189
  return Qnil;
182
190
  else
183
191
  {
184
-
192
+ if (s_body.bodyBuf != NULL)
193
+ free (s_body.bodyBuf);
194
+
195
+ s_body.bodyBuf = NULL;
196
+ s_body.bodyLen = -1;
197
+ s_body.bodyCurrentLen = 0;
198
+ s_body.curPos = 0;
199
+
185
200
  pid = getpid();
186
201
  if ( pid != s_pid )
187
202
  {
188
203
  s_pid = pid;
189
204
  rb_funcall( Qnil, rb_intern( "srand" ), 0 );
190
205
  }
191
-
206
+
192
207
  setup_cgi_env( s_req_data );
193
208
  return s_req;
194
209
  }
195
-
196
210
  }
197
211
 
198
212
  /*
199
- static int chdir_file( const char * pFile )
200
- {
201
- char * p = strrchr( pFile, '/' );
202
- int ret;
203
- if ( !p )
204
- return -1;
205
- *p = 0;
206
- ret = chdir( pFile );
207
- *p = '/';
208
- return ret;
209
- }
210
- */
213
+ * static int chdir_file( const char * pFile )
214
+ * {
215
+ * char * p = strrchr( pFile, '/' );
216
+ * int ret;
217
+ * if ( !p )
218
+ * return -1;
219
+ *p = 0;
220
+ ret = chdir( pFile );
221
+ *p = '/';
222
+ return ret;
223
+ }
224
+ */
211
225
 
212
226
  static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str)
213
227
  {
@@ -224,18 +238,19 @@ static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str)
224
238
 
225
239
  static VALUE lsapi_process( VALUE self )
226
240
  {
227
- lsapi_data *data;
241
+ /* lsapi_data *data;
228
242
  const char * pScriptPath;
229
243
  Data_Get_Struct(self,lsapi_data, data);
230
244
  pScriptPath = LSAPI_GetScriptFileName_r( data->req );
231
- /*
232
- if ( chdir_file( pScriptPath ) == -1 )
233
- {
234
- lsapi_send_error( 404 );
235
- }
236
- rb_load_file( pScriptPath );
237
245
  */
238
- return Qnil;
246
+ /*
247
+ * if ( chdir_file( pScriptPath ) == -1 )
248
+ * {
249
+ * lsapi_send_error( 404 );
250
+ * }
251
+ * rb_load_file( pScriptPath );
252
+ */
253
+ return Qnil;
239
254
  }
240
255
 
241
256
 
@@ -256,9 +271,9 @@ static VALUE lsapi_write( VALUE self, VALUE str )
256
271
  lsapi_data *data;
257
272
  int len;
258
273
  Data_Get_Struct(self,lsapi_data, data);
259
- /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */
274
+ /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */
260
275
  if (TYPE(str) != T_STRING)
261
- str = rb_obj_as_string(str);
276
+ str = rb_obj_as_string(str);
262
277
  len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) );
263
278
  return INT2NUM( len );
264
279
  }
@@ -267,13 +282,13 @@ static VALUE lsapi_print( int argc, VALUE *argv, VALUE out )
267
282
  {
268
283
  int i;
269
284
  VALUE line;
270
-
285
+
271
286
  /* if no argument given, print `$_' */
272
287
  if (argc == 0)
273
288
  {
274
- argc = 1;
275
- line = rb_lastline_get();
276
- argv = &line;
289
+ argc = 1;
290
+ line = rb_lastline_get();
291
+ argv = &line;
277
292
  }
278
293
  for (i = 0; i<argc; i++)
279
294
  {
@@ -283,19 +298,19 @@ static VALUE lsapi_print( int argc, VALUE *argv, VALUE out )
283
298
  }
284
299
  switch (TYPE(argv[i]))
285
300
  {
286
- case T_NIL:
287
- lsapi_write(out, rb_str_new2("nil"));
288
- break;
289
- default:
290
- lsapi_write(out, argv[i]);
291
- break;
301
+ case T_NIL:
302
+ lsapi_write(out, rb_str_new2("nil"));
303
+ break;
304
+ default:
305
+ lsapi_write(out, argv[i]);
306
+ break;
292
307
  }
293
308
  }
294
309
  if (!NIL_P(rb_output_rs))
295
310
  {
296
311
  lsapi_write(out, rb_output_rs);
297
312
  }
298
-
313
+
299
314
  return Qnil;
300
315
  }
301
316
 
@@ -312,8 +327,8 @@ static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur )
312
327
  {
313
328
  VALUE tmp;
314
329
  long i;
315
-
316
- if (recur)
330
+
331
+ if (recur)
317
332
  {
318
333
  tmp = rb_str_new2("[...]");
319
334
  rb_io_puts(1, &tmp, out);
@@ -325,22 +340,22 @@ static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur )
325
340
  rb_io_puts(1, &tmp, out);
326
341
  }
327
342
  return Qnil;
328
-
343
+
329
344
  }
330
345
  #else
331
346
  static VALUE lsapi_puts_ary(VALUE ary, VALUE out)
332
347
  {
333
348
  VALUE tmp;
334
349
  int i;
335
-
350
+
336
351
  for (i=0; i<RARRAY_LEN(ary); i++)
337
352
  {
338
353
  tmp = RARRAY_PTR(ary)[i];
339
- if (rb_inspecting_p(tmp))
354
+ if (rb_inspecting_p(tmp))
340
355
  {
341
- tmp = rb_str_new2("[...]");
342
- }
343
- lsapi_puts(1, &tmp, out);
356
+ tmp = rb_str_new2("[...]");
357
+ }
358
+ lsapi_puts(1, &tmp, out);
344
359
  }
345
360
  return Qnil;
346
361
  }
@@ -350,7 +365,7 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
350
365
  {
351
366
  int i;
352
367
  VALUE line;
353
-
368
+
354
369
  /* if no argument given, print newline. */
355
370
  if (argc == 0)
356
371
  {
@@ -361,19 +376,19 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
361
376
  {
362
377
  switch (TYPE(argv[i]))
363
378
  {
364
- case T_NIL:
365
- line = rb_str_new2("nil");
366
- break;
367
- case T_ARRAY:
379
+ case T_NIL:
380
+ line = rb_str_new2("nil");
381
+ break;
382
+ case T_ARRAY:
368
383
  #if defined( RUBY_19 ) || defined( RUBY_2 )
369
- rb_exec_recursive(lsapi_puts_ary, argv[i], out);
384
+ rb_exec_recursive(lsapi_puts_ary, argv[i], out);
370
385
  #else
371
- rb_protect_inspect(lsapi_puts_ary, argv[i], out);
386
+ rb_protect_inspect(lsapi_puts_ary, argv[i], out);
372
387
  #endif
373
- continue;
374
- default:
375
- line = argv[i];
376
- break;
388
+ continue;
389
+ default:
390
+ line = argv[i];
391
+ break;
377
392
  }
378
393
  line = rb_obj_as_string(line);
379
394
  lsapi_write(out, line);
@@ -382,7 +397,7 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
382
397
  lsapi_write(out, rb_default_rs);
383
398
  }
384
399
  }
385
-
400
+
386
401
  return Qnil;
387
402
  }
388
403
 
@@ -395,10 +410,10 @@ static VALUE lsapi_addstr(VALUE out, VALUE str)
395
410
 
396
411
  static VALUE lsapi_flush( VALUE self )
397
412
  {
398
- /*
399
- lsapi_data *data;
400
- Data_Get_Struct(self,lsapi_data, data);
401
- */
413
+ /*
414
+ * lsapi_data *data;
415
+ * Data_Get_Struct(self,lsapi_data, data);
416
+ */
402
417
  LSAPI_Flush_r( &g_req );
403
418
  return Qnil;
404
419
  }
@@ -406,10 +421,10 @@ static VALUE lsapi_flush( VALUE self )
406
421
  static VALUE lsapi_getc( VALUE self )
407
422
  {
408
423
  int ch;
409
- /*
410
- lsapi_data *data;
411
- Data_Get_Struct(self,lsapi_data, data);
412
- */
424
+ /*
425
+ * lsapi_data *data;
426
+ * Data_Get_Struct(self,lsapi_data, data);
427
+ */
413
428
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
414
429
  {
415
430
  rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
@@ -420,88 +435,246 @@ static VALUE lsapi_getc( VALUE self )
420
435
  return INT2NUM( ch );
421
436
  }
422
437
 
438
+ static inline int isBodyWriteToFile()
439
+ {
440
+ return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0));
441
+ }
442
+
443
+ //create a temp file and open it, if failed, fd = -1
444
+ static inline int createTempFile()
445
+ {
446
+ int fd = -1;
447
+ char *sfn = strdup(sTempFile);
448
+
449
+ if ((fd = mkstemp(sfn)) == -1)
450
+ {
451
+ fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
452
+ }
453
+ else
454
+ unlink(sfn);
455
+
456
+ free(sfn);
457
+ return fd;
458
+ }
459
+
460
+ //return 1 if error occured!
461
+ //if already created, always OK (0)
462
+ static int createBodyBuf()
463
+ {
464
+ int fd = -1;
465
+ if (s_body.bodyLen == -1)
466
+ {
467
+ s_body.bodyLen = LSAPI_GetReqBodyLen_r(&g_req);
468
+ //Error if get a zeor length, should not happen
469
+ if (s_body.bodyLen < 0)
470
+ {
471
+ //Wrong bode length will be treated as 0
472
+ s_body.bodyLen = 0;
473
+ }
474
+
475
+ if (s_body.bodyLen > 0)
476
+ {
477
+ if (isBodyWriteToFile())
478
+ {
479
+ //create file mapping
480
+ fd = createTempFile();
481
+ if (fd == -1)
482
+ {
483
+ return 1;
484
+ }
485
+ ftruncate(fd, s_body.bodyLen);
486
+ s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
487
+ if (s_body.bodyBuf == MAP_FAILED)
488
+ {
489
+ perror("File mapping failed. \n");
490
+ close(fd);
491
+ return 1;
492
+ }
493
+
494
+ close(fd); //close since needn't it anymore
495
+ }
496
+ else
497
+ {
498
+ s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char));
499
+ if (s_body.bodyBuf == NULL)
500
+ {
501
+ perror("Memory calloc error");
502
+ return 1;
503
+ }
504
+ }
505
+ }
506
+ }
507
+
508
+ return 0;
509
+ }
510
+
511
+ static inline int isAllBodyRead()
512
+ {
513
+ return (s_body.bodyCurrentLen < s_body.bodyLen)? 0 : 1;
514
+ }
515
+
516
+ static inline int isEofBodyBuf()
517
+ {
518
+ return (s_body.curPos < s_body.bodyLen) ? 0 : 1;
519
+ }
520
+ //try to read length as times pagesize (such as 8KB * N)
521
+ static int readBodyBuf(const int needRead)
522
+ {
523
+ const int blockSize = 8192;
524
+ char *buff = s_body.bodyBuf + s_body.bodyCurrentLen;
525
+ int nRead;
526
+ int readMore = (needRead + blockSize -1) / blockSize * blockSize;
527
+ int remain = LSAPI_GetReqBodyRemain_r( &g_req );
528
+ //Only when not enough left, needReadChange will be changed!!!
529
+ if (remain < readMore)
530
+ readMore = remain;
531
+
532
+ if ( readMore <= 0 )
533
+ return 0;
534
+
535
+ nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore);
536
+ if ( nRead > 0 )
537
+ s_body.bodyCurrentLen += nRead;
538
+
539
+ return nRead;
540
+ }
541
+
423
542
  static VALUE lsapi_gets( VALUE self )
424
543
  {
425
544
  VALUE str;
426
- int getLF = 0;
427
- char buff[4096];
428
- int len;
545
+ const int blkSize = 4096;
546
+ int n;
547
+ char *p = NULL;
548
+
429
549
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
430
550
  {
431
551
  rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
432
552
  }
433
- if ( LSAPI_GetReqBodyRemain_r( &g_req ) <= 0 )
553
+
554
+ if (createBodyBuf() == 1)
555
+ {
434
556
  return Qnil;
435
- str = rb_str_buf_new( 1024 );
557
+ }
558
+
559
+ //comment:
560
+ while((p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1)) == NULL)
561
+ {
562
+ if (isAllBodyRead() == 1)
563
+ break;
564
+ //read one page and check, then reply
565
+ readBodyBuf(blkSize);
566
+ }
567
+
568
+ p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1);
569
+ if (p != NULL)
570
+ n = p - s_body.bodyBuf - s_body.curPos + 1;
571
+ else
572
+ n = s_body.bodyCurrentLen - s_body.curPos;
573
+
574
+ str = rb_str_buf_new( n );
436
575
  OBJ_TAINT(str);
437
- while( !getLF )
576
+
577
+ if (n > 0)
438
578
  {
439
- len = LSAPI_ReqBodyGetLine_r( &g_req, buff, 4096, &getLF );
440
- if ( len > 0 )
441
- rb_str_buf_cat( str, buff, len );
442
-
579
+ rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n );
580
+ s_body.curPos += n;
443
581
  }
444
- if (RSTRING_LEN(str) == 0)
445
- return Qnil;
582
+
446
583
  return str;
447
584
  }
448
585
 
449
-
450
586
  static VALUE lsapi_read(int argc, VALUE *argv, VALUE self)
451
587
  {
452
588
  VALUE str;
453
589
  int n;
454
- int remain;
455
- char buff[8192];
456
-
590
+ int needRead;
591
+ int nRead;
592
+
457
593
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
458
594
  {
459
595
  rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
460
596
  }
461
-
462
-
463
- remain = LSAPI_GetReqBodyRemain_r( &g_req );
464
- if ( remain <= 0 )
597
+
598
+ if (createBodyBuf() == 1)
599
+ {
465
600
  return Qnil;
466
- if (argc != 0)
601
+ }
602
+
603
+ //we need to consider these 4 cases:
604
+ //1, need all data since argc == 0, we may have all data 2, or not
605
+ //3, need a length of data (argv >= 1), we may have enough data already read, 4, or not
606
+ if (argc == 0)
607
+ n = s_body.bodyLen - s_body.curPos;
608
+ else
467
609
  {
468
- n = NUM2INT(argv[0]);
469
- if ( remain > n )
470
- remain = n;
610
+ n = NUM2INT(argv[0]); //request that length from currentpos
611
+ if (n < 0)
612
+ return Qnil;
613
+ if (n > s_body.bodyLen - s_body.curPos)
614
+ n = s_body.bodyLen - s_body.curPos;
471
615
  }
472
- str = rb_str_buf_new( remain );
616
+ needRead = s_body.curPos + n - s_body.bodyCurrentLen;
617
+ if (needRead < 0)
618
+ needRead = 0;
619
+
620
+ str = rb_str_buf_new( n );
473
621
  OBJ_TAINT(str);
474
- while( remain > 0 )
622
+ if (n == 0)
623
+ return str;
624
+
625
+ //copy already have part first
626
+ if (n - needRead != 0)
475
627
  {
476
- n = LSAPI_ReadReqBody_r(&g_req, buff,
477
- (remain > 8192)?8192:remain );
478
- if ( n > 0 )
479
- {
480
- rb_str_buf_cat( str, buff, n );
481
- remain -= n;
482
- }
483
- else if ( n <= 0 )
628
+ rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n - needRead);
629
+ s_body.curPos += (n - needRead);
630
+ }
631
+
632
+ if (needRead > 0)
633
+ {
634
+ //try to read needRead, but may be less (changed) when read the end of the data
635
+ nRead = readBodyBuf(needRead);
636
+ if (nRead > 0)
484
637
  {
485
- /* FIXME: broken connection */
486
- break;
638
+ n = ((nRead < needRead) ? nRead : needRead);
639
+ rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n );
640
+ s_body.curPos += n;
487
641
  }
488
642
  }
489
- if (RSTRING_LEN(str) == 0)
490
- return Qnil;
643
+
491
644
  return str;
492
645
  }
493
646
 
494
- static VALUE lsapi_eof(VALUE self)
647
+ static VALUE lsapi_rewind(VALUE self)
648
+ {
649
+ s_body.curPos = 0;
650
+ return self;
651
+ }
652
+
653
+ static VALUE lsapi_each(int argc, VALUE *argv, VALUE self)
495
654
  {
496
- /*
497
- lsapi_data *data;
655
+ VALUE str;
656
+ lsapi_rewind(self);
657
+
658
+ while(isEofBodyBuf() != 1)
659
+ {
660
+ str = lsapi_gets(self);
661
+ rb_yield(str);
662
+ }
663
+ return self;
498
664
 
499
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
500
- {
501
- rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
502
- }
503
- Data_Get_Struct(self, lsapi_data, data);
504
- */
665
+ }
666
+
667
+ static VALUE lsapi_eof(VALUE self)
668
+ {
669
+ /*
670
+ * lsapi_data *data;
671
+ *
672
+ * if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
673
+ * {
674
+ * rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
675
+ }
676
+ Data_Get_Struct(self, lsapi_data, data);
677
+ */
505
678
  return (LSAPI_GetReqBodyRemain_r( &g_req ) <= 0) ? Qtrue : Qfalse;
506
679
  }
507
680
 
@@ -527,7 +700,22 @@ static VALUE lsapi_setsync(VALUE self,VALUE sync)
527
700
 
528
701
  static VALUE lsapi_close(VALUE self)
529
702
  {
530
- LSAPI_Flush_r( &g_req );
703
+ LSAPI_Flush_r( &g_req );
704
+ if (isBodyWriteToFile())
705
+ {
706
+ //msync(s_body.bodyBuf, s_body.bodyLen, MS_SYNC);
707
+ //sleep(5);
708
+ munmap(s_body.bodyBuf, s_body.bodyLen);
709
+ }
710
+ else
711
+ free(s_body.bodyBuf);
712
+
713
+ s_body.bodyBuf = NULL;
714
+ s_body.bodyLen = -1;
715
+ s_body.bodyCurrentLen = 0;
716
+ s_body.curPos = 0;
717
+ //Should the temp be deleted here?!
718
+
531
719
  return Qnil;
532
720
  }
533
721
 
@@ -540,32 +728,72 @@ static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self)
540
728
  /* constant silence hack */
541
729
  orig_verbose = (VALUE)ruby_verbose;
542
730
  ruby_verbose = Qnil;
543
-
731
+
544
732
  rb_define_global_const("STDERR", orig_stderr);
545
-
733
+
546
734
  ruby_verbose = (VALUE)orig_verbose;
547
-
735
+
548
736
  return rb_funcall2( orig_stderr, rb_intern( "reopen" ), argc, argv );
549
-
737
+
550
738
  }
551
739
  return self;
552
740
  }
553
741
 
742
+ static void readMaxBodyBufLength()
743
+ {
744
+ int n;
745
+ const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" );
746
+ if ( p )
747
+ {
748
+ n = atoi( p );
749
+ if (n > 0)
750
+ {
751
+ if (strstr(p, "M") || strstr(p, "m"))
752
+ MAX_BODYBUF_LENGTH = n * 1024 * 1024;
753
+ else if (strstr(p, "K") || strstr(p, "k"))
754
+ MAX_BODYBUF_LENGTH = n * 1024;
755
+ else
756
+ MAX_BODYBUF_LENGTH = n;
757
+ }
758
+ }
759
+ }
554
760
 
761
+ static void readTempFileTemplate()
762
+ {
763
+ const char *p = getenv( "LSAPI_TEMPFILE" );
764
+ if (p == NULL || strlen(p) > 1024 - 7)
765
+ p = "/tmp/lsapi.XXXXXX";
766
+
767
+ strcpy(sTempFile, p);
768
+ if (strlen(p) <= 6 || strcmp(p + (strlen(p) - 6), "XXXXXX") != 0)
769
+ strcat(sTempFile, ".XXXXXX");
770
+ }
555
771
 
772
+ static void initBodyBuf()
773
+ {
774
+ s_body.bodyBuf = NULL;
775
+ s_body.bodyLen = -1;
776
+ s_body.bodyCurrentLen = 0;
777
+ s_body.curPos = 0;
778
+ }
556
779
  void Init_lsapi()
557
780
  {
558
- VALUE remove_env;
559
781
  VALUE orig_verbose;
560
782
  char * p;
561
-
562
783
  LSAPI_Init();
563
-
564
- //LSAPI_Init_Env_Parameters( rb_thread_select );
784
+ initBodyBuf();
785
+
786
+ readMaxBodyBufLength();
787
+ readTempFileTemplate();
788
+
789
+ #ifdef rb_thread_select
790
+ LSAPI_Init_Env_Parameters( rb_thread_select );
791
+ #else
565
792
  LSAPI_Init_Env_Parameters( select );
566
-
793
+ #endif
794
+
567
795
  s_pid = getpid();
568
-
796
+
569
797
  p = getenv( "RAILS_ROOT" );
570
798
  if ( p )
571
799
  {
@@ -574,8 +802,8 @@ void Init_lsapi()
574
802
  }
575
803
  if ( p || getenv( "RAILS_ENV" ) )
576
804
  s_fn_add_env = add_env_rails;
577
-
578
-
805
+
806
+
579
807
  orig_stdin = rb_stdin;
580
808
  orig_stdout = rb_stdout;
581
809
  orig_stderr = rb_stderr;
@@ -587,20 +815,15 @@ void Init_lsapi()
587
815
 
588
816
  /* tell the garbage collector it is a global variable, do not recycle it. */
589
817
  rb_global_variable(&env_copy);
590
-
591
- rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_INTERFACE", 17),
592
- rb_tainted_str_new("CGI/1.2", 7));
593
818
 
594
- /* Do not need those environments after initialization */
595
- /* remove_env = rb_str_new( "RAILS_ROOT", 10 );
596
- rb_funcall( env_copy, rb_intern( "delete" ), 1, remove_env );
597
- */
598
-
819
+ rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_Irewindable_input.rbNTERFACE", 17),
820
+ rb_tainted_str_new("CGI/1.2", 7));
821
+
599
822
  rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1);
600
-
823
+
601
824
  cLSAPI = rb_define_class("LSAPI", rb_cObject);
602
825
  rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0);
603
-
826
+
604
827
  rb_define_method(cLSAPI, "process", lsapi_process, 0 );
605
828
  /* rb_define_method(cLSAPI, "initialize", lsapi_initialize, 0); */
606
829
  rb_define_method(cLSAPI, "putc", lsapi_putc, 1);
@@ -613,11 +836,14 @@ void Init_lsapi()
613
836
  rb_define_method(cLSAPI, "getc", lsapi_getc, 0);
614
837
  /* rb_define_method(cLSAPI, "ungetc", lsapi_ungetc, 1); */
615
838
  rb_define_method(cLSAPI, "gets", lsapi_gets, 0);
616
-
839
+
617
840
  //TEST: adding readline function to make irb happy?
618
841
  /*rb_define_method(cLSAPI, "readline", lsapi_gets, 0); */
619
-
842
+
620
843
  rb_define_method(cLSAPI, "read", lsapi_read, -1);
844
+ rb_define_method(cLSAPI, "rewind", lsapi_rewind, 0);
845
+ rb_define_method(cLSAPI, "each", lsapi_each, 0);
846
+
621
847
  rb_define_method(cLSAPI, "eof", lsapi_eof, 0);
622
848
  rb_define_method(cLSAPI, "eof?", lsapi_eof, 0);
623
849
  rb_define_method(cLSAPI, "close", lsapi_close, 0);
@@ -629,34 +855,34 @@ void Init_lsapi()
629
855
  rb_define_method(cLSAPI, "sync=", lsapi_setsync, 1);
630
856
  rb_define_method(cLSAPI, "reopen", lsapi_reopen, -1 );
631
857
 
632
-
858
+
633
859
  s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data );
634
860
  s_req_data->req = &g_req;
635
861
  s_req_data->fn_write = LSAPI_Write_r;
636
862
  rb_stdin = rb_stdout = s_req;
637
-
863
+
638
864
  #if RUBY_VERSION_CODE < 180
639
865
  rb_defout = s_req;
640
866
  #endif
641
867
  rb_global_variable(&s_req );
642
-
868
+
643
869
  s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data );
644
870
  s_stderr_data->req = &g_req;
645
871
  s_stderr_data->fn_write = LSAPI_Write_Stderr_r;
646
872
  rb_stderr = s_req_stderr;
647
873
  rb_global_variable(&s_req_stderr );
648
-
874
+
649
875
  /* constant silence hack */
650
876
  orig_verbose = (VALUE)ruby_verbose;
651
877
  ruby_verbose = Qnil;
652
-
878
+
653
879
  lsapi_env = rb_hash_new();
654
880
  clear_env();
655
881
  /* redefine ENV using a hash table, should be faster than char **environment */
656
882
  rb_define_global_const("ENV", lsapi_env);
657
883
 
658
884
  rb_define_global_const("STDERR", rb_stderr);
659
-
885
+
660
886
  ruby_verbose = (VALUE)orig_verbose;
661
887
 
662
888
  return;