ry / ebb fork watch download tarball
public this repo is viewable by everyone
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
Removed TEMPFILE!

Ebb is now passing off handling of uploads to the framework. Do what you
want. Maybe you even reject the request before reading the rest. This is 
as
Chris intendend it with Rack and it simplifies my code. Seems to fix an
upload bug I was experiencing.
ryah (author)
about 1 month ago
commit  9bc8da2c4cab2643f399f26dffdef1f48cdf6d7a
tree    86569ce7eac26c728e76c70cbc78ee0847d639d8
parent  1a53c2b86d8cb383167163cff4acc0bfaa344a86
...
99
100
101
 
102
103
104
...
154
155
156
157
 
 
 
 
 
 
 
 
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
 
 
 
 
 
173
 
 
174
175
176
177
 
178
179
180
181
182
183
184
185
 
186
187
188
...
227
228
229
 
 
 
 
 
...
99
100
101
102
103
104
105
...
155
156
157
 
158
159
160
161
162
163
164
165
166
167
168
 
 
 
 
 
 
 
 
 
 
 
 
169
170
171
172
173
174
175
176
177
178
179
 
180
181
182
183
 
 
 
 
 
184
185
186
187
...
226
227
228
229
230
231
232
233
0
@@ -99,6 +99,7 @@ module Ebb
0
   end
0
   
0
   class Client
0
+ attr_reader :fd, :body_head, :content_length
0
     BASE_ENV = {
0
       'SERVER_NAME' => '0.0.0.0',
0
       'SCRIPT_NAME' => '',
0
@@ -154,35 +155,33 @@ module Ebb
0
   
0
   class RequestBody
0
     def initialize(client)
0
- @client = client
0
+ @content_length = client.content_length
0
+ if client.body_head
0
+ @body_head = StringIO.new(client.body_head)
0
+ if @body_head.length < @content_length
0
+ @socket = IO.new(client.fd)
0
+ end
0
+ end
0
+ @total_read = 0
0
     end
0
     
0
     def read(len = nil)
0
- if @io
0
- @io.read(len)
0
- else
0
- if len.nil?
0
- s = ''
0
- while(chunk = read(10*1024)) do
0
- s << chunk
0
- end
0
- s
0
- else
0
- FFI::client_read_input(@client, len)
0
- end
0
+ to_read = len.nil? ? @content_length - @total_read : min(len, @content_length - @total_read)
0
+ return nil if to_read == 0 or @body_head.nil?
0
+ unless out = @body_head.read(to_read)
0
+ return nil if @socket.nil?
0
+ out = @socket.read(to_read)
0
       end
0
+ @total_read += out.length
0
+ out
0
     end
0
     
0
     def gets
0
- io.gets
0
+ raise NotImplemented
0
     end
0
     
0
     def each(&block)
0
- io.each(&block)
0
- end
0
-
0
- def io
0
- @io ||= StringIO.new(read)
0
+ raise NotImplemented
0
     end
0
   end
0
   
0
@@ -227,3 +226,8 @@ module Ebb
0
     505 => 'HTTP Version not supported'
0
   }.freeze
0
 end
0
+
0
+# cause i don't want to create an array
0
+def min(a,b)
0
+ a > b ? b : a
0
+end
...
17
18
19
20
21
22
23
24
 
25
26
27
...
91
92
93
94
95
96
97
 
98
99
100
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
216
217
218
219
 
220
221
222
...
228
229
230
231
 
 
 
 
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
342
343
344
345
 
346
347
348
...
355
356
357
358
359
360
361
362
...
631
632
633
634
635
636
637
638
639
640
641
642
...
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
...
17
18
19
 
 
 
20
21
22
23
24
25
...
89
90
91
 
 
 
 
92
93
94
95
...
111
112
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
115
116
...
131
132
133
 
134
135
136
137
...
143
144
145
 
146
147
148
149
150
 
151
152
153
 
 
 
 
 
 
 
 
 
154
155
156
...
250
251
252
 
253
254
255
256
...
263
264
265
 
 
266
267
268
...
537
538
539
 
 
 
 
 
 
540
541
542
...
601
602
603
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
604
605
606
0
@@ -17,11 +17,9 @@
0
 #include <signal.h>
0
 #include <assert.h>
0
 
0
-#include <pthread.h>
0
-#include <glib.h>
0
-
0
 #define EV_STANDALONE 1
0
 #include <ev.c>
0
+#include <glib.h>
0
 
0
 #include "parser.h"
0
 #include "ebb.h"
0
@@ -91,10 +89,7 @@ static void dispatch(ebb_client *client)
0
     return;
0
   client->in_use = TRUE;
0
   
0
- /* decide if to use keep-alive or not */
0
-
0
-
0
-
0
+ /* XXX decide if to use keep-alive or not? */
0
   
0
   server->request_cb(client, server->request_cb_data);
0
 }
0
@@ -116,86 +111,6 @@ static void on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
0
 #define client_finished_parsing http_parser_is_finished(&client->parser)
0
 #define total_request_size (client->parser.content_length + client->parser.nread)
0
 
0
-static void* read_body_into_file(void *_client)
0
-{
0
- ebb_client *client = (ebb_client*)_client;
0
- FILE *tmpfile;
0
- char *filename = "/tmp/.ebb_upload.XXXXXX";
0
-
0
- assert(client->open);
0
- assert(client->server->open);
0
- assert(client->parser.content_length > 0);
0
- assert(client_finished_parsing);
0
-
0
- /* set blocking socket */
0
- int flags = fcntl(client->fd, F_GETFL, 0);
0
- int ret = fcntl(client->fd, F_SETFL, flags & ~O_NONBLOCK);
0
- assert(0 <= ret);
0
-
0
- if(0 > mkstemp(filename)) {
0
- perror("mkstemp()");
0
- ebb_client_close(client);
0
- return NULL;
0
- }
0
- client->upload_filename = strdup(filename);
0
- tmpfile = fopen(filename, "w+");
0
- if(tmpfile == NULL) {
0
- perror("opening tempfile for uplaod");
0
- ebb_client_close(client);
0
- return NULL;
0
- }
0
- client->upload_file = tmpfile;
0
-
0
- size_t body_head_length = client->read - client->parser.nread;
0
- size_t written = 0, r;
0
- while(written < body_head_length) {
0
- r = fwrite( client->request_buffer + sizeof(char)*(client->parser.nread + written)
0
- , sizeof(char)
0
- , body_head_length - written
0
- , tmpfile
0
- );
0
- if(r <= 0) {
0
- ebb_client_close(client);
0
- return NULL;
0
- }
0
- written += r;
0
- }
0
-
0
- int bufsize = 5*1024;
0
- char buffer[bufsize];
0
- size_t received;
0
- while(written < client->parser.content_length) {
0
- received = recv(client->fd
0
- , buffer
0
- , min(client->parser.content_length - written, bufsize)
0
- , 0
0
- );
0
- if(received < 0) goto error;
0
- client->read += received;
0
-
0
- ssize_t w = 0;
0
- int rv;
0
- while(w < received) {
0
- rv = fwrite( buffer + w*sizeof(char)
0
- , sizeof(char)
0
- , received - w
0
- , tmpfile
0
- );
0
- if(rv <= 0) goto error;
0
- w += rv;
0
- }
0
- written += received;
0
- }
0
- rewind(tmpfile);
0
- // g_debug("%d bytes written to file %s", written, client->upload_filename);
0
- dispatch(client);
0
- return NULL;
0
-error:
0
- ebb_client_close(client);
0
- return NULL;
0
-}
0
-
0
-
0
 static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents)
0
 {
0
   ebb_client *client = (ebb_client*)(watcher->data);
0
@@ -216,7 +131,7 @@ static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents
0
   client->read += read;
0
   ev_timer_again(loop, &client->timeout_watcher);
0
   
0
- if(client->read == EBB_BUFFERSIZE) goto error;
0
+ // if(client->read == EBB_BUFFERSIZE) goto error;
0
   
0
   if(FALSE == client_finished_parsing) {
0
     http_parser_execute( &client->parser
0
@@ -228,21 +143,14 @@ static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents
0
   }
0
   
0
   if(client_finished_parsing) {
0
- if(total_request_size == client->read) {
0
+ assert(client->read <= total_request_size);
0
+ if(total_request_size == client->read || total_request_size > EBB_BUFFERSIZE) {
0
+ client->body_head = client->request_buffer + client->parser.nread;
0
+ client->body_head_len = client->read - client->parser.nread;
0
       ev_io_stop(loop, watcher);
0
- client->nread_from_body = 0;
0
       dispatch(client);
0
       return;
0
     }
0
- if(total_request_size > EBB_BUFFERSIZE ) {
0
- /* read body into file - in a thread */
0
- ev_io_stop(loop, watcher);
0
- pthread_t thread;
0
- int ret = pthread_create(&thread, NULL, read_body_into_file, client);
0
- assert(0 <= ret);
0
- pthread_detach(thread);
0
- return;
0
- }
0
   }
0
   return;
0
 error:
0
@@ -342,7 +250,7 @@ static void client_init(ebb_client *client)
0
   
0
   /* OTHER */
0
   client->env_size = 0;
0
- client->read = client->nread_from_body = 0;
0
+ client->read = 0;
0
   if(client->request_buffer == NULL) {
0
     /* Only allocate the request_buffer once */
0
     client->request_buffer = (char*)malloc(EBB_BUFFERSIZE);
0
@@ -355,8 +263,6 @@ static void client_init(ebb_client *client)
0
     g_string_free(client->response_buffer, TRUE);
0
   client->response_buffer = g_string_new("");
0
   
0
- client->upload_filename = NULL;
0
-
0
   /* SETUP READ AND TIMEOUT WATCHERS */
0
   client->write_watcher.data = client;
0
   ev_init (&client->write_watcher, on_client_writable);
0
@@ -631,12 +537,6 @@ void ebb_client_close(ebb_client *client)
0
     ev_io_stop(client->server->loop, &client->write_watcher);
0
     ev_timer_stop(client->server->loop, &client->timeout_watcher);
0
     
0
- if(client->upload_filename) {
0
- fclose(client->upload_file);
0
- unlink(client->upload_filename);
0
- client->upload_file = NULL;
0
- client->upload_filename = NULL;
0
- }
0
     client->ip = NULL;
0
     
0
     g_string_free(client->response_buffer, TRUE);
0
@@ -701,36 +601,6 @@ void ebb_client_write_body(ebb_client *client, const char *data, int length)
0
   }
0
 }
0
 
0
-
0
-/* pass an allocated buffer and the length to read. this function will try to
0
- * fill the buffer with that length of data read from the body of the request.
0
- * the return value says how much was actually written.
0
- */
0
-int ebb_client_read(ebb_client *client, char *buffer, int length)
0
-{
0
- size_t read;
0
-
0
- assert(client->in_use);
0
- if(!client->open) return -1;
0
- assert(client_finished_parsing);
0
-
0
- if(client->upload_file) {
0
- read = fread(buffer, 1, length, client->upload_file);
0
- /* TODO error checking! */
0
- return read;
0
- } else {
0
- char* request_body = client->request_buffer + client->parser.nread;
0
-
0
- read = ramp(min(length, client->parser.content_length - client->nread_from_body));
0
- memcpy( buffer
0
- , request_body + client->nread_from_body
0
- , read
0
- );
0
- client->nread_from_body += read;
0
- return read;
0
- }
0
-}
0
-
0
 // int ebb_client_should_keep_alive(ebb_client*)
0
 // {
0
 // /* TODO - return boolean */
...
51
52
53
54
 
55
56
57
 
 
58
59
60
...
51
52
53
 
54
55
 
 
56
57
58
59
60
0
@@ -51,10 +51,10 @@ struct ebb_client {
0
   
0
   char *request_buffer;
0
   ev_io read_watcher;
0
- size_t read, nread_from_body;
0
+ size_t read;
0
   
0
- char *upload_filename;
0
- FILE *upload_file;
0
+ char *body_head;
0
+ size_t body_head_len;
0
   
0
   ev_io write_watcher;
0
   GString *response_buffer;
...
61
62
63
 
 
 
 
 
 
64
65
66
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
303
304
305
306
307
308
309
...
61
62
63
64
65
66
67
68
69
70
71
72
...
220
221
222
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
224
225
...
285
286
287
 
288
289
290
0
@@ -61,6 +61,12 @@ static void detach_idle_watcher()
0
 void request_cb(ebb_client *client, void *data)
0
 {
0
   VALUE rb_client = Data_Wrap_Struct(cClient, 0, 0, client);
0
+
0
+ rb_iv_set(rb_client, "@fd", INT2FIX(client->fd));
0
+ rb_iv_set(rb_client, "@content_length", INT2FIX(client->parser.content_length));
0
+ if(client->body_head_len > 0)
0
+ rb_iv_set(rb_client, "@body_head", rb_str_new(client->body_head, client->body_head_len));
0
+
0
   rb_ary_push(waiting_clients, rb_client);
0
   attach_idle_watcher();
0
 }
0
@@ -214,30 +220,6 @@ VALUE client_env(VALUE _, VALUE rb_client)
0
   return env;
0
 }
0
 
0
-
0
-VALUE client_read_input(VALUE _, VALUE client, VALUE size)
0
-{
0
- ebb_client *_client;
0
- GString *_string;
0
- VALUE string;
0
- int _size = FIX2INT(size);
0
- Data_Get_Struct(client, ebb_client, _client);
0
-
0
- string = rb_str_buf_new( _size );
0
- int nread = ebb_client_read(_client, RSTRING_PTR(string), _size);
0
-#if RUBY_VERSION_CODE < 190
0
- RSTRING(string)->len = nread;
0
-#else
0
- rb_str_set_len(string, nread);
0
-#endif
0
-
0
- if(nread < 0)
0
- rb_raise(rb_eRuntimeError,"There was a problem reading from input (bad tmp file?)");
0
- if(nread == 0)
0
- return Qnil;
0
- return string;
0
-}
0
-
0
 VALUE client_write_status(VALUE _, VALUE client, VALUE status, VALUE reason_phrase)
0
 {
0
   ebb_client *_client;
0
@@ -303,7 +285,6 @@ void Init_ebb_ext()
0
   rb_define_singleton_method(mFFI, "server_waiting_clients", server_waiting_clients, 0);
0
   
0
   cClient = rb_define_class_under(mEbb, "Client", rb_cObject);
0
- rb_define_singleton_method(mFFI, "client_read_input", client_read_input, 2);
0
   rb_define_singleton_method(mFFI, "client_write_status", client_write_status, 3);
0
   rb_define_singleton_method(mFFI, "client_write_header", client_write_header, 3);
0
   rb_define_singleton_method(mFFI, "client_write_body", client_write_body, 2);

Comments

    No one has commented yet.