ruby-lsapi 4.2 → 4.3

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