ruby-lsapi 4.1 → 5.1

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.
@@ -1,21 +1,21 @@
1
1
  /*
2
- Copyright (c) 2005, Lite Speed Technologies Inc.
2
+ Copyright (c) 2002-2018, Lite Speed Technologies Inc.
3
3
  All rights reserved.
4
4
 
5
5
  Redistribution and use in source and binary forms, with or without
6
6
  modification, are permitted provided that the following conditions are
7
- met:
7
+ met:
8
8
 
9
9
  * Redistributions of source code must retain the above copyright
10
- notice, this list of conditions and the following disclaimer.
10
+ notice, this list of conditions and the following disclaimer.
11
11
  * Redistributions in binary form must reproduce the above
12
12
  copyright notice, this list of conditions and the following
13
13
  disclaimer in the documentation and/or other materials provided
14
- with the distribution.
14
+ with the distribution.
15
15
  * Neither the name of the Lite Speed Technologies Inc nor the
16
16
  names of its contributors may be used to endorse or promote
17
17
  products derived from this software without specific prior
18
- written permission.
18
+ written permission.
19
19
 
20
20
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
21
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -27,17 +27,9 @@ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
27
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
28
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
29
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
31
  */
32
32
 
33
- /***************************************************************************
34
- lsapilib.h - description
35
- -------------------
36
- begin : Mon Feb 21 2005
37
- copyright : (C) 2005 by George Wang
38
- email : gwang@litespeedtech.com
39
- ***************************************************************************/
40
-
41
33
 
42
34
  #ifndef _LSAPILIB_H_
43
35
  #define _LSAPILIB_H_
@@ -46,9 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46
38
  extern "C" {
47
39
  #endif
48
40
 
49
- #include <stddef.h>
50
- #include <lsapidef.h>
41
+ #include "lsapidef.h"
51
42
 
43
+ #include <stddef.h>
52
44
  #include <sys/time.h>
53
45
  #include <sys/types.h>
54
46
 
@@ -60,8 +52,8 @@ struct LSAPI_key_value_pair
60
52
  int valLen;
61
53
  };
62
54
 
63
-
64
- #define LSAPI_MAX_RESP_HEADERS 100
55
+ struct lsapi_child_status;
56
+ #define LSAPI_MAX_RESP_HEADERS 1000
65
57
 
66
58
  typedef struct lsapi_request
67
59
  {
@@ -73,7 +65,7 @@ typedef struct lsapi_request
73
65
 
74
66
  char * m_pReqBuf;
75
67
  int m_reqBufSize;
76
-
68
+
77
69
  char * m_pRespBuf;
78
70
  char * m_pRespBufEnd;
79
71
  char * m_pRespBufPos;
@@ -81,12 +73,13 @@ typedef struct lsapi_request
81
73
  char * m_pRespHeaderBuf;
82
74
  char * m_pRespHeaderBufEnd;
83
75
  char * m_pRespHeaderBufPos;
76
+ struct lsapi_child_status * child_status;
84
77
 
85
78
 
86
79
  struct iovec * m_pIovec;
87
80
  struct iovec * m_pIovecEnd;
88
81
  struct iovec * m_pIovecCur;
89
- struct iovec * m_pIovecToWrite;
82
+ struct iovec * m_pIovecToWrite;
90
83
 
91
84
  struct lsapi_packet_header * m_respPktHeaderEnd;
92
85
 
@@ -98,7 +91,7 @@ typedef struct lsapi_request
98
91
 
99
92
  struct lsapi_http_header_index * m_pHeaderIndex;
100
93
  struct lsapi_header_offset * m_pUnknownHeader;
101
-
94
+
102
95
  char * m_pScriptFile;
103
96
  char * m_pScriptName;
104
97
  char * m_pQueryString;
@@ -110,9 +103,9 @@ typedef struct lsapi_request
110
103
  off_t m_reqBodyRead;
111
104
  int m_bufProcessed;
112
105
  int m_bufRead;
113
-
106
+
114
107
  struct lsapi_packet_header m_respPktHeader[5];
115
-
108
+
116
109
  struct lsapi_resp_header m_respHeader;
117
110
  short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS];
118
111
  void * m_pAppData;
@@ -158,7 +151,6 @@ int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
158
151
  LSAPI_CB_EnvHandler fn, void * arg );
159
152
 
160
153
  char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name );
161
-
162
154
 
163
155
  ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t len );
164
156
 
@@ -179,9 +171,12 @@ int LSAPI_Flush_r( LSAPI_Request * pReq );
179
171
 
180
172
  int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len );
181
173
 
182
- int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
174
+ int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
183
175
  const char * pHeaderValue );
184
176
 
177
+ int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders,
178
+ const char * pBody, int bodyLen );
179
+
185
180
  static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code )
186
181
  {
187
182
  if ( !pReq )
@@ -253,6 +248,10 @@ static inline off_t LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq )
253
248
  }
254
249
 
255
250
 
251
+ int LSAPI_End_Response_r(LSAPI_Request * pReq);
252
+
253
+
254
+
256
255
  int LSAPI_Is_Listen(void);
257
256
 
258
257
  static inline int LSAPI_Accept( void )
@@ -280,28 +279,28 @@ static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg )
280
279
  static inline char * LSAPI_GetEnv( const char * name )
281
280
  { return LSAPI_GetEnv_r( &g_req, name ); }
282
281
 
283
- static inline char * LSAPI_GetQueryString()
282
+ static inline char * LSAPI_GetQueryString(void)
284
283
  { return LSAPI_GetQueryString_r( &g_req ); }
285
284
 
286
- static inline char * LSAPI_GetScriptFileName()
285
+ static inline char * LSAPI_GetScriptFileName(void)
287
286
  { return LSAPI_GetScriptFileName_r( &g_req ); }
288
287
 
289
- static inline char * LSAPI_GetScriptName()
288
+ static inline char * LSAPI_GetScriptName(void)
290
289
  { return LSAPI_GetScriptName_r( &g_req ); }
291
290
 
292
- static inline char * LSAPI_GetRequestMethod()
291
+ static inline char * LSAPI_GetRequestMethod(void)
293
292
  { return LSAPI_GetRequestMethod_r( &g_req ); }
294
293
 
295
- static inline off_t LSAPI_GetReqBodyLen()
294
+ static inline off_t LSAPI_GetReqBodyLen(void)
296
295
  { return LSAPI_GetReqBodyLen_r( &g_req ); }
297
296
 
298
- static inline off_t LSAPI_GetReqBodyRemain()
297
+ static inline off_t LSAPI_GetReqBodyRemain(void)
299
298
  { return LSAPI_GetReqBodyRemain_r( &g_req ); }
300
299
 
301
300
  static inline ssize_t LSAPI_ReadReqBody( char * pBuf, size_t len )
302
301
  { return LSAPI_ReadReqBody_r( &g_req, pBuf, len ); }
303
302
 
304
- static inline int LSAPI_ReqBodyGetChar()
303
+ static inline int LSAPI_ReqBodyGetChar(void)
305
304
  { return LSAPI_ReqBodyGetChar_r( &g_req ); }
306
305
 
307
306
  static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF )
@@ -317,13 +316,13 @@ static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len )
317
316
 
318
317
  static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size )
319
318
  {
320
- return LSAPI_sendfile_r(&g_req, fdIn, off, size );
319
+ return LSAPI_sendfile_r(&g_req, fdIn, off, size );
321
320
  }
322
321
 
323
322
  static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len )
324
323
  { return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); }
325
324
 
326
- static inline int LSAPI_Flush()
325
+ static inline int LSAPI_Flush(void)
327
326
  { return LSAPI_Flush_r( &g_req ); }
328
327
 
329
328
  static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
@@ -332,6 +331,12 @@ static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
332
331
  static inline int LSAPI_SetRespStatus( int code )
333
332
  { return LSAPI_SetRespStatus_r( &g_req, code ); }
334
333
 
334
+ static inline int LSAPI_ErrResponse( int code, const char ** pRespHeaders, const char * pBody, int bodyLen )
335
+ { return LSAPI_ErrResponse_r( &g_req, code, pRespHeaders, pBody, bodyLen ); }
336
+
337
+ static inline int LSAPI_End_Response(void)
338
+ { return LSAPI_End_Response_r( &g_req ); }
339
+
335
340
  int LSAPI_IsRunning(void);
336
341
 
337
342
  int LSAPI_CreateListenSock( const char * pBind, int backlog );
@@ -344,6 +349,8 @@ void LSAPI_Set_Server_fd( int fd );
344
349
 
345
350
  int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq );
346
351
 
352
+ void LSAPI_No_Check_ppid(void);
353
+
347
354
  void LSAPI_Set_Max_Reqs( int reqs );
348
355
 
349
356
  void LSAPI_Set_Max_Idle( int secs );
@@ -360,9 +367,46 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp );
360
367
 
361
368
  void LSAPI_Set_Slow_Req_Msecs( int msecs );
362
369
 
363
- int LSAPI_Get_Slow_Req_Msecs( );
370
+ int LSAPI_Get_Slow_Req_Msecs(void);
371
+
372
+ int LSAPI_is_suEXEC_Daemon(void);
373
+
374
+ int LSAPI_Set_Restored_Parent_Pid(int pid);
375
+
376
+ typedef void (*LSAPI_On_Timer_pf)(int *forked_child_pid);
377
+ void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf);
378
+
379
+ int LSAPI_Inc_Req_Processed(int cnt);
380
+
381
+ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq);
382
+
383
+ int LSAPI_Postfork_Child(LSAPI_Request * pReq);
384
+
385
+ int LSAPI_Postfork_Parent(LSAPI_Request * pReq);
386
+
387
+ #define LSAPI_LOG_LEVEL_BITS 0xff
388
+ #define LSAPI_LOG_FLAG_NONE 0
389
+ #define LSAPI_LOG_FLAG_DEBUG 1
390
+ #define LSAPI_LOG_FLAG_INFO 2
391
+ #define LSAPI_LOG_FLAG_NOTICE 3
392
+ #define LSAPI_LOG_FLAG_WARN 4
393
+ #define LSAPI_LOG_FLAG_ERROR 5
394
+ #define LSAPI_LOG_FLAG_CRIT 6
395
+ #define LSAPI_LOG_FLAG_FATAL 7
396
+
397
+ #define LSAPI_LOG_TIMESTAMP_BITS (0xff00)
398
+ #define LSAPI_LOG_TIMESTAMP_FULL (0x100)
399
+ #define LSAPI_LOG_TIMESTAMP_HMS (0x200)
400
+ #define LSAPI_LOG_TIMESTAMP_STDERR (0x400)
401
+
402
+ #define LSAPI_LOG_PID (0x10000)
403
+
404
+ void LSAPI_Log(int flag, const char * fmt, ...)
405
+ #if __GNUC__
406
+ __attribute__((format(printf, 2, 3)))
407
+ #endif
408
+ ;
364
409
 
365
- int LSAPI_is_suEXEC_Daemon();
366
410
 
367
411
  #if defined (c_plusplus) || defined (__cplusplus)
368
412
  }
@@ -1,7 +1,7 @@
1
1
 
2
2
  #include "ruby.h"
3
3
 
4
- #ifdef RUBY_19
4
+ #if defined( RUBY_19 ) || defined( RUBY_2 )
5
5
  #include <ruby/util.h>
6
6
  #else
7
7
  #include "util.h"
@@ -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
 
@@ -43,11 +46,9 @@ typedef struct lsapi_data
43
46
  {
44
47
  LSAPI_Request * req;
45
48
  VALUE env;
46
- int (* fn_write)( LSAPI_Request *, const char * , int );
47
-
49
+ ssize_t (* fn_write)( LSAPI_Request *, const char * , size_t );
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,63 @@ 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
- /*
199
- static int chdir_file( const char * pFile )
212
+
213
+ static VALUE lsapi_s_accept_new_conn(VALUE self)
214
+ {
215
+ if (LSAPI_Accept_Before_Fork(&g_req) == -1 )
216
+ return Qnil;
217
+ else
218
+ return s_req;
219
+ }
220
+
221
+
222
+ static VALUE lsapi_s_postfork_child(VALUE self)
200
223
  {
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;
224
+ LSAPI_Postfork_Child(&g_req);
225
+ return s_req;
209
226
  }
210
- */
227
+
228
+
229
+ static VALUE lsapi_s_postfork_parent(VALUE self)
230
+ {
231
+ LSAPI_Postfork_Parent(&g_req);
232
+ return s_req;
233
+ }
234
+
235
+
236
+ /*
237
+ * static int chdir_file( const char * pFile )
238
+ * {
239
+ * char * p = strrchr( pFile, '/' );
240
+ * int ret;
241
+ * if ( !p )
242
+ * return -1;
243
+ *p = 0;
244
+ ret = chdir( pFile );
245
+ *p = '/';
246
+ return ret;
247
+ }
248
+ */
211
249
 
212
250
  static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str)
213
251
  {
@@ -217,25 +255,26 @@ static VALUE lsapi_eval_string_wrap(VALUE self, VALUE str)
217
255
  }
218
256
  else
219
257
  {
220
- Check_SafeStr(str);
258
+ SafeStringValue(str);
221
259
  }
222
260
  return rb_eval_string_wrap(StringValuePtr(str), NULL);
223
261
  }
224
262
 
225
263
  static VALUE lsapi_process( VALUE self )
226
264
  {
227
- lsapi_data *data;
265
+ /* lsapi_data *data;
228
266
  const char * pScriptPath;
229
267
  Data_Get_Struct(self,lsapi_data, data);
230
268
  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
269
  */
238
- return Qnil;
270
+ /*
271
+ * if ( chdir_file( pScriptPath ) == -1 )
272
+ * {
273
+ * lsapi_send_error( 404 );
274
+ * }
275
+ * rb_load_file( pScriptPath );
276
+ */
277
+ return Qnil;
239
278
  }
240
279
 
241
280
 
@@ -256,9 +295,9 @@ static VALUE lsapi_write( VALUE self, VALUE str )
256
295
  lsapi_data *data;
257
296
  int len;
258
297
  Data_Get_Struct(self,lsapi_data, data);
259
- /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */
298
+ /* len = LSAPI_Write_r( data->req, RSTRING_PTR(str), RSTRING_LEN(str) ); */
260
299
  if (TYPE(str) != T_STRING)
261
- str = rb_obj_as_string(str);
300
+ str = rb_obj_as_string(str);
262
301
  len = (*data->fn_write)( data->req, RSTRING_PTR(str), RSTRING_LEN(str) );
263
302
  return INT2NUM( len );
264
303
  }
@@ -267,13 +306,13 @@ static VALUE lsapi_print( int argc, VALUE *argv, VALUE out )
267
306
  {
268
307
  int i;
269
308
  VALUE line;
270
-
309
+
271
310
  /* if no argument given, print `$_' */
272
311
  if (argc == 0)
273
312
  {
274
- argc = 1;
275
- line = rb_lastline_get();
276
- argv = &line;
313
+ argc = 1;
314
+ line = rb_lastline_get();
315
+ argv = &line;
277
316
  }
278
317
  for (i = 0; i<argc; i++)
279
318
  {
@@ -283,19 +322,19 @@ static VALUE lsapi_print( int argc, VALUE *argv, VALUE out )
283
322
  }
284
323
  switch (TYPE(argv[i]))
285
324
  {
286
- case T_NIL:
287
- lsapi_write(out, rb_str_new2("nil"));
288
- break;
289
- default:
290
- lsapi_write(out, argv[i]);
291
- break;
325
+ case T_NIL:
326
+ lsapi_write(out, rb_str_new2("nil"));
327
+ break;
328
+ default:
329
+ lsapi_write(out, argv[i]);
330
+ break;
292
331
  }
293
332
  }
294
333
  if (!NIL_P(rb_output_rs))
295
334
  {
296
335
  lsapi_write(out, rb_output_rs);
297
336
  }
298
-
337
+
299
338
  return Qnil;
300
339
  }
301
340
 
@@ -307,13 +346,13 @@ static VALUE lsapi_printf(int argc, VALUE *argv, VALUE out)
307
346
 
308
347
  static VALUE lsapi_puts _((int, VALUE*, VALUE));
309
348
 
310
- #ifdef RUBY_19
349
+ #if defined( RUBY_19 ) || defined( RUBY_2 )
311
350
  static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur )
312
351
  {
313
352
  VALUE tmp;
314
353
  long i;
315
-
316
- if (recur)
354
+
355
+ if (recur)
317
356
  {
318
357
  tmp = rb_str_new2("[...]");
319
358
  rb_io_puts(1, &tmp, out);
@@ -325,22 +364,22 @@ static VALUE lsapi_puts_ary(VALUE ary, VALUE out, int recur )
325
364
  rb_io_puts(1, &tmp, out);
326
365
  }
327
366
  return Qnil;
328
-
367
+
329
368
  }
330
369
  #else
331
370
  static VALUE lsapi_puts_ary(VALUE ary, VALUE out)
332
371
  {
333
372
  VALUE tmp;
334
373
  int i;
335
-
374
+
336
375
  for (i=0; i<RARRAY_LEN(ary); i++)
337
376
  {
338
377
  tmp = RARRAY_PTR(ary)[i];
339
- if (rb_inspecting_p(tmp))
378
+ if (rb_inspecting_p(tmp))
340
379
  {
341
- tmp = rb_str_new2("[...]");
342
- }
343
- lsapi_puts(1, &tmp, out);
380
+ tmp = rb_str_new2("[...]");
381
+ }
382
+ lsapi_puts(1, &tmp, out);
344
383
  }
345
384
  return Qnil;
346
385
  }
@@ -350,7 +389,7 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
350
389
  {
351
390
  int i;
352
391
  VALUE line;
353
-
392
+
354
393
  /* if no argument given, print newline. */
355
394
  if (argc == 0)
356
395
  {
@@ -361,19 +400,19 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
361
400
  {
362
401
  switch (TYPE(argv[i]))
363
402
  {
364
- case T_NIL:
365
- line = rb_str_new2("nil");
366
- break;
367
- case T_ARRAY:
368
- #ifdef RUBY_19
369
- rb_exec_recursive(lsapi_puts_ary, argv[i], out);
403
+ case T_NIL:
404
+ line = rb_str_new2("nil");
405
+ break;
406
+ case T_ARRAY:
407
+ #if defined( RUBY_19 ) || defined( RUBY_2 )
408
+ rb_exec_recursive(lsapi_puts_ary, argv[i], out);
370
409
  #else
371
- rb_protect_inspect(lsapi_puts_ary, argv[i], out);
410
+ rb_protect_inspect(lsapi_puts_ary, argv[i], out);
372
411
  #endif
373
- continue;
374
- default:
375
- line = argv[i];
376
- break;
412
+ continue;
413
+ default:
414
+ line = argv[i];
415
+ break;
377
416
  }
378
417
  line = rb_obj_as_string(line);
379
418
  lsapi_write(out, line);
@@ -382,7 +421,7 @@ static VALUE lsapi_puts(int argc, VALUE *argv, VALUE out)
382
421
  lsapi_write(out, rb_default_rs);
383
422
  }
384
423
  }
385
-
424
+
386
425
  return Qnil;
387
426
  }
388
427
 
@@ -395,10 +434,10 @@ static VALUE lsapi_addstr(VALUE out, VALUE str)
395
434
 
396
435
  static VALUE lsapi_flush( VALUE self )
397
436
  {
398
- /*
399
- lsapi_data *data;
400
- Data_Get_Struct(self,lsapi_data, data);
401
- */
437
+ /*
438
+ * lsapi_data *data;
439
+ * Data_Get_Struct(self,lsapi_data, data);
440
+ */
402
441
  LSAPI_Flush_r( &g_req );
403
442
  return Qnil;
404
443
  }
@@ -406,10 +445,10 @@ static VALUE lsapi_flush( VALUE self )
406
445
  static VALUE lsapi_getc( VALUE self )
407
446
  {
408
447
  int ch;
409
- /*
410
- lsapi_data *data;
411
- Data_Get_Struct(self,lsapi_data, data);
412
- */
448
+ /*
449
+ * lsapi_data *data;
450
+ * Data_Get_Struct(self,lsapi_data, data);
451
+ */
413
452
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
414
453
  {
415
454
  rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
@@ -420,89 +459,251 @@ static VALUE lsapi_getc( VALUE self )
420
459
  return INT2NUM( ch );
421
460
  }
422
461
 
462
+ static inline int isBodyWriteToFile()
463
+ {
464
+ return ((s_body.bodyLen >= MAX_BODYBUF_LENGTH)? (1): (0));
465
+ }
466
+
467
+ //create a temp file and open it, if failed, fd = -1
468
+ static inline int createTempFile()
469
+ {
470
+ int fd = -1;
471
+ char *sfn = strdup(sTempFile);
472
+
473
+ if ((fd = mkstemp(sfn)) == -1)
474
+ {
475
+ fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
476
+ }
477
+ else
478
+ unlink(sfn);
479
+
480
+ free(sfn);
481
+ return fd;
482
+ }
483
+
484
+ //return 1 if error occured!
485
+ //if already created, always OK (0)
486
+ static int createBodyBuf()
487
+ {
488
+ int fd = -1;
489
+ if (s_body.bodyLen == -1)
490
+ {
491
+ s_body.bodyLen = LSAPI_GetReqBodyLen_r(&g_req);
492
+ //Error if get a zeor length, should not happen
493
+ if (s_body.bodyLen < 0)
494
+ {
495
+ //Wrong bode length will be treated as 0
496
+ s_body.bodyLen = 0;
497
+ }
498
+
499
+ if (s_body.bodyLen > 0)
500
+ {
501
+ if (isBodyWriteToFile())
502
+ {
503
+ //create file mapping
504
+ fd = createTempFile();
505
+ if (fd == -1)
506
+ {
507
+ return 1;
508
+ }
509
+ if (ftruncate(fd, s_body.bodyLen) == 0)
510
+ {
511
+ perror("ftruncate() failed. \n");
512
+ close(fd);
513
+ return 1;
514
+ }
515
+ s_body.bodyBuf = mmap(NULL, s_body.bodyLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
516
+ if (s_body.bodyBuf == MAP_FAILED)
517
+ {
518
+ perror("File mapping failed. \n");
519
+ close(fd);
520
+ return 1;
521
+ }
522
+ close(fd); //close since needn't it anymore
523
+ }
524
+ else
525
+ {
526
+ s_body.bodyBuf = (char *)calloc(s_body.bodyLen, sizeof(char));
527
+ if (s_body.bodyBuf == NULL)
528
+ {
529
+ perror("Memory calloc error");
530
+ return 1;
531
+ }
532
+ }
533
+ }
534
+ }
535
+
536
+ return 0;
537
+ }
538
+
539
+ static inline int isAllBodyRead()
540
+ {
541
+ return (s_body.bodyCurrentLen < s_body.bodyLen)? 0 : 1;
542
+ }
543
+
544
+ static inline int isEofBodyBuf()
545
+ {
546
+ return (s_body.curPos < s_body.bodyLen) ? 0 : 1;
547
+ }
548
+ //try to read length as times pagesize (such as 8KB * N)
549
+ static int readBodyBuf(const int needRead)
550
+ {
551
+ const int blockSize = 8192;
552
+ char *buff = s_body.bodyBuf + s_body.bodyCurrentLen;
553
+ int nRead;
554
+ int readMore = (needRead + blockSize -1) / blockSize * blockSize;
555
+ int remain = LSAPI_GetReqBodyRemain_r( &g_req );
556
+ //Only when not enough left, needReadChange will be changed!!!
557
+ if (remain < readMore)
558
+ readMore = remain;
559
+
560
+ if ( readMore <= 0 )
561
+ return 0;
562
+
563
+ nRead = LSAPI_ReadReqBody_r(&g_req, buff, readMore);
564
+ if ( nRead > 0 )
565
+ s_body.bodyCurrentLen += nRead;
566
+
567
+ return nRead;
568
+ }
569
+
423
570
  static VALUE lsapi_gets( VALUE self )
424
571
  {
425
572
  VALUE str;
426
- int getLF = 0;
427
- char buff[4096];
428
- int len;
573
+ const int blkSize = 4096;
574
+ int n;
575
+ char *p = NULL;
576
+
429
577
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
430
578
  {
431
579
  rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
432
580
  }
433
- if ( LSAPI_GetReqBodyRemain_r( &g_req ) <= 0 )
581
+
582
+ if (createBodyBuf() == 1)
583
+ {
434
584
  return Qnil;
435
- str = rb_str_buf_new( 1024 );
585
+ }
586
+
587
+ //comment:
588
+ while((p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1)) == NULL)
589
+ {
590
+ if (isAllBodyRead() == 1)
591
+ break;
592
+ //read one page and check, then reply
593
+ readBodyBuf(blkSize);
594
+ }
595
+
596
+ p = memmem(s_body.bodyBuf + s_body.curPos, s_body.bodyCurrentLen - s_body.curPos, "\n", 1);
597
+ if (p != NULL)
598
+ n = p - s_body.bodyBuf - s_body.curPos + 1;
599
+ else
600
+ n = s_body.bodyCurrentLen - s_body.curPos;
601
+
602
+ str = rb_str_buf_new( n );
436
603
  OBJ_TAINT(str);
437
- while( !getLF )
604
+
605
+ if (n > 0)
438
606
  {
439
- len = LSAPI_ReqBodyGetLine_r( &g_req, buff, 4096, &getLF );
440
- if ( len > 0 )
441
- rb_str_buf_cat( str, buff, len );
442
-
607
+ rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n );
608
+ s_body.curPos += n;
443
609
  }
444
- if (RSTRING_LEN(str) == 0)
445
- return Qnil;
610
+
446
611
  return str;
447
612
  }
448
613
 
449
-
450
614
  static VALUE lsapi_read(int argc, VALUE *argv, VALUE self)
451
615
  {
452
616
  VALUE str;
453
617
  int n;
454
- int remain;
455
- char buff[8192];
456
-
618
+ int needRead;
619
+ int nRead;
620
+
457
621
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
458
622
  {
459
623
  rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
460
624
  }
461
-
462
-
463
- remain = LSAPI_GetReqBodyRemain_r( &g_req );
464
- if ( remain <= 0 )
625
+
626
+ if (createBodyBuf() == 1)
627
+ {
465
628
  return Qnil;
466
- if (argc != 0)
629
+ }
630
+
631
+ //we need to consider these 4 cases:
632
+ //1, need all data since argc == 0, we may have all data 2, or not
633
+ //3, need a length of data (argv >= 1), we may have enough data already read, 4, or not
634
+ if (argc == 0)
635
+ n = s_body.bodyLen - s_body.curPos;
636
+ else
467
637
  {
468
- n = NUM2INT(argv[0]);
469
- if ( remain > n )
470
- remain = n;
638
+ n = NUM2INT(argv[0]); //request that length from currentpos
639
+ if (n < 0)
640
+ return Qnil;
641
+ if (n > s_body.bodyLen - s_body.curPos)
642
+ n = s_body.bodyLen - s_body.curPos;
471
643
  }
472
- str = rb_str_buf_new( remain );
644
+ needRead = s_body.curPos + n - s_body.bodyCurrentLen;
645
+ if (needRead < 0)
646
+ needRead = 0;
647
+
648
+ str = rb_str_buf_new( n );
473
649
  OBJ_TAINT(str);
474
- while( remain > 0 )
650
+ if (n == 0)
651
+ return str;
652
+
653
+ //copy already have part first
654
+ if (n - needRead != 0)
475
655
  {
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 )
656
+ rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n - needRead);
657
+ s_body.curPos += (n - needRead);
658
+ }
659
+
660
+ if (needRead > 0)
661
+ {
662
+ //try to read needRead, but may be less (changed) when read the end of the data
663
+ nRead = readBodyBuf(needRead);
664
+ if (nRead > 0)
484
665
  {
485
- /* FIXME: broken connection */
486
- break;
666
+ n = ((nRead < needRead) ? nRead : needRead);
667
+ rb_str_buf_cat( str, s_body.bodyBuf + s_body.curPos, n );
668
+ s_body.curPos += n;
487
669
  }
488
670
  }
489
- if (RSTRING_LEN(str) == 0)
490
- return Qnil;
671
+
491
672
  return str;
492
673
  }
493
674
 
494
- static VALUE lsapi_eof(VALUE self)
675
+ static VALUE lsapi_rewind(VALUE self)
676
+ {
677
+ s_body.curPos = 0;
678
+ return self;
679
+ }
680
+
681
+ static VALUE lsapi_each(int argc, VALUE *argv, VALUE self)
495
682
  {
496
- /*
497
- lsapi_data *data;
683
+ VALUE str;
684
+ lsapi_rewind(self);
685
+
686
+ while(isEofBodyBuf() != 1)
687
+ {
688
+ str = lsapi_gets(self);
689
+ rb_yield(str);
690
+ }
691
+ return self;
498
692
 
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
- */
505
- return (LSAPI_GetReqBodyRemain( &g_req ) <= 0) ? Qtrue : Qfalse;
693
+ }
694
+
695
+ static VALUE lsapi_eof(VALUE self)
696
+ {
697
+ /*
698
+ * lsapi_data *data;
699
+ *
700
+ * if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
701
+ * {
702
+ * rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
703
+ }
704
+ Data_Get_Struct(self, lsapi_data, data);
705
+ */
706
+ return (LSAPI_GetReqBodyRemain_r( &g_req ) <= 0) ? Qtrue : Qfalse;
506
707
  }
507
708
 
508
709
  static VALUE lsapi_binmode(VALUE self)
@@ -527,7 +728,22 @@ static VALUE lsapi_setsync(VALUE self,VALUE sync)
527
728
 
528
729
  static VALUE lsapi_close(VALUE self)
529
730
  {
530
- LSAPI_Flush_r( &g_req );
731
+ LSAPI_Flush_r( &g_req );
732
+ if (isBodyWriteToFile())
733
+ {
734
+ //msync(s_body.bodyBuf, s_body.bodyLen, MS_SYNC);
735
+ //sleep(5);
736
+ munmap(s_body.bodyBuf, s_body.bodyLen);
737
+ }
738
+ else
739
+ free(s_body.bodyBuf);
740
+
741
+ s_body.bodyBuf = NULL;
742
+ s_body.bodyLen = -1;
743
+ s_body.bodyCurrentLen = 0;
744
+ s_body.curPos = 0;
745
+ //Should the temp be deleted here?!
746
+
531
747
  return Qnil;
532
748
  }
533
749
 
@@ -540,41 +756,86 @@ static VALUE lsapi_reopen( int argc, VALUE *argv, VALUE self)
540
756
  /* constant silence hack */
541
757
  orig_verbose = (VALUE)ruby_verbose;
542
758
  ruby_verbose = Qnil;
543
-
759
+
544
760
  rb_define_global_const("STDERR", orig_stderr);
545
-
761
+
546
762
  ruby_verbose = (VALUE)orig_verbose;
547
-
763
+
548
764
  return rb_funcall2( orig_stderr, rb_intern( "reopen" ), argc, argv );
549
-
765
+
550
766
  }
551
767
  return self;
552
768
  }
553
769
 
770
+ static void readMaxBodyBufLength()
771
+ {
772
+ int n;
773
+ const char *p = getenv( "LSAPI_MAX_BODYBUF_LENGTH" );
774
+ if ( p )
775
+ {
776
+ n = atoi( p );
777
+ if (n > 0)
778
+ {
779
+ if (strstr(p, "M") || strstr(p, "m"))
780
+ MAX_BODYBUF_LENGTH = n * 1024 * 1024;
781
+ else if (strstr(p, "K") || strstr(p, "k"))
782
+ MAX_BODYBUF_LENGTH = n * 1024;
783
+ else
784
+ MAX_BODYBUF_LENGTH = n;
785
+ }
786
+ }
787
+ }
554
788
 
789
+ static void readTempFileTemplate()
790
+ {
791
+ const char *p = getenv( "LSAPI_TEMPFILE" );
792
+ if (p == NULL || strlen(p) > 1024 - 7)
793
+ p = "/tmp/lsapi.XXXXXX";
794
+
795
+ strcpy(sTempFile, p);
796
+ if (strlen(p) <= 6 || strcmp(p + (strlen(p) - 6), "XXXXXX") != 0)
797
+ strcat(sTempFile, ".XXXXXX");
798
+ }
555
799
 
800
+ static void initBodyBuf()
801
+ {
802
+ s_body.bodyBuf = NULL;
803
+ s_body.bodyLen = -1;
804
+ s_body.bodyCurrentLen = 0;
805
+ s_body.curPos = 0;
806
+ }
556
807
  void Init_lsapi()
557
808
  {
558
- VALUE remove_env;
559
809
  VALUE orig_verbose;
560
810
  char * p;
561
-
811
+ int prefork = 0;
562
812
  LSAPI_Init();
563
-
813
+ initBodyBuf();
814
+
815
+ readMaxBodyBufLength();
816
+ readTempFileTemplate();
817
+
818
+ #ifdef rb_thread_select
564
819
  LSAPI_Init_Env_Parameters( rb_thread_select );
565
-
820
+ #else
821
+ LSAPI_Init_Env_Parameters( select );
822
+ #endif
823
+
566
824
  s_pid = getpid();
567
-
568
- p = getenv( "RAILS_ROOT" );
825
+
826
+ p = getenv( "RACK_ROOT" );
569
827
  if ( p )
570
828
  {
571
829
  if ( chdir( p ) == -1 )
572
830
  perror( "chdir()" );
573
831
  }
574
- if ( p || getenv( "RAILS_ENV" ) )
832
+ if ( p || getenv( "RACK_ENV" ) )
575
833
  s_fn_add_env = add_env_rails;
576
-
577
-
834
+
835
+ p = getenv("LSAPI_CHILDREN");
836
+ if (p && atoi(p) > 1)
837
+ prefork = 1;
838
+
578
839
  orig_stdin = rb_stdin;
579
840
  orig_stdout = rb_stdout;
580
841
  orig_stderr = rb_stderr;
@@ -586,19 +847,20 @@ void Init_lsapi()
586
847
 
587
848
  /* tell the garbage collector it is a global variable, do not recycle it. */
588
849
  rb_global_variable(&env_copy);
589
-
590
- rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_INTERFACE", 17),
591
- rb_tainted_str_new("CGI/1.2", 7));
592
850
 
593
- /* Do not need those environments after initialization */
594
- /* remove_env = rb_str_new( "RAILS_ROOT", 10 );
595
- rb_funcall( env_copy, rb_intern( "delete" ), 1, remove_env );
596
- */
597
-
851
+ rb_hash_aset( env_copy,rb_tainted_str_new("GATEWAY_Irewindable_input.rbNTERFACE", 17),
852
+ rb_tainted_str_new("CGI/1.2", 7));
853
+
598
854
  rb_define_global_function("eval_string_wrap", lsapi_eval_string_wrap, 1);
599
-
855
+
600
856
  cLSAPI = rb_define_class("LSAPI", rb_cObject);
601
857
  rb_define_singleton_method(cLSAPI, "accept", lsapi_s_accept, 0);
858
+ if (prefork)
859
+ {
860
+ rb_define_singleton_method(cLSAPI, "accept_new_connection", lsapi_s_accept_new_conn, 0);
861
+ rb_define_singleton_method(cLSAPI, "postfork_child", lsapi_s_postfork_child, 0);
862
+ rb_define_singleton_method(cLSAPI, "postfork_parent", lsapi_s_postfork_parent, 0);
863
+ }
602
864
 
603
865
  rb_define_method(cLSAPI, "process", lsapi_process, 0 );
604
866
  /* rb_define_method(cLSAPI, "initialize", lsapi_initialize, 0); */
@@ -612,11 +874,14 @@ void Init_lsapi()
612
874
  rb_define_method(cLSAPI, "getc", lsapi_getc, 0);
613
875
  /* rb_define_method(cLSAPI, "ungetc", lsapi_ungetc, 1); */
614
876
  rb_define_method(cLSAPI, "gets", lsapi_gets, 0);
615
-
877
+
616
878
  //TEST: adding readline function to make irb happy?
617
879
  /*rb_define_method(cLSAPI, "readline", lsapi_gets, 0); */
618
-
880
+
619
881
  rb_define_method(cLSAPI, "read", lsapi_read, -1);
882
+ rb_define_method(cLSAPI, "rewind", lsapi_rewind, 0);
883
+ rb_define_method(cLSAPI, "each", lsapi_each, 0);
884
+
620
885
  rb_define_method(cLSAPI, "eof", lsapi_eof, 0);
621
886
  rb_define_method(cLSAPI, "eof?", lsapi_eof, 0);
622
887
  rb_define_method(cLSAPI, "close", lsapi_close, 0);
@@ -628,34 +893,34 @@ void Init_lsapi()
628
893
  rb_define_method(cLSAPI, "sync=", lsapi_setsync, 1);
629
894
  rb_define_method(cLSAPI, "reopen", lsapi_reopen, -1 );
630
895
 
631
-
896
+
632
897
  s_req = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_req_data );
633
898
  s_req_data->req = &g_req;
634
899
  s_req_data->fn_write = LSAPI_Write_r;
635
900
  rb_stdin = rb_stdout = s_req;
636
-
901
+
637
902
  #if RUBY_VERSION_CODE < 180
638
903
  rb_defout = s_req;
639
904
  #endif
640
905
  rb_global_variable(&s_req );
641
-
906
+
642
907
  s_req_stderr = Data_Make_Struct( cLSAPI, lsapi_data, lsapi_mark, free, s_stderr_data );
643
908
  s_stderr_data->req = &g_req;
644
909
  s_stderr_data->fn_write = LSAPI_Write_Stderr_r;
645
910
  rb_stderr = s_req_stderr;
646
911
  rb_global_variable(&s_req_stderr );
647
-
912
+
648
913
  /* constant silence hack */
649
914
  orig_verbose = (VALUE)ruby_verbose;
650
915
  ruby_verbose = Qnil;
651
-
916
+
652
917
  lsapi_env = rb_hash_new();
653
918
  clear_env();
654
919
  /* redefine ENV using a hash table, should be faster than char **environment */
655
920
  rb_define_global_const("ENV", lsapi_env);
656
921
 
657
922
  rb_define_global_const("STDERR", rb_stderr);
658
-
923
+
659
924
  ruby_verbose = (VALUE)orig_verbose;
660
925
 
661
926
  return;