public
Fork of ry/ebb
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/gnosek/ebb.git
Remove begin_transmission API

Instead set client->body_written = TRUE when ebb_client_release is called.

In side ebb_client_write_body() we will start the write watcher if it is 
not
already active and also write \r\n once all the headers are written. This
seems to clean up a lot of mess and confusion.
Ryan Dahl (author)
Fri Mar 21 17:48:31 -0700 2008
commit  eb87a28b1e30f2303bc5c11684ba50ec87f01427
tree    80e4a223d3e5c5ab5541ef2f0efce67e400d7a0a
parent  cebd9c9cba0549bc78c1459f85e8ea3eb6330771
...
45
46
47
48
49
50
51
52
53
54
55
 
56
 
57
58
 
59
60
61
62
63
 
64
65
66
 
67
68
69
70
 
71
72
73
74
 
75
 
76
77
78
...
117
118
119
120
121
 
 
122
123
124
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
...
45
46
47
 
 
 
 
 
 
 
 
48
49
50
51
52
53
54
55
56
57
58
59
60
 
61
62
63
 
 
 
64
65
 
 
 
66
67
68
69
70
71
...
110
111
112
 
 
113
114
115
116
117
...
120
121
122
 
 
 
 
 
 
 
 
123
124
125
0
@@ -45,34 +45,27 @@ module Ebb
0
   end
0
   
0
   def self.process(app, client)
0
- begin
0
- status, headers, body = app.call(client.env)
0
- rescue
0
- raise if $DEBUG
0
- status = 500
0
- headers = {'Content-Type' => 'text/plain'}
0
- body = "Internal Server Error\n"
0
- end
0
+ status, headers, body = app.call(client.env)
0
     
0
+ # Write the status
0
     client.write_status(status)
0
     
0
+ # Add Content-Length to the headers.
0
     if headers.respond_to?(:[]=) and body.respond_to?(:length) and status != 304
0
       headers['Connection'] = 'close'
0
       headers['Content-Length'] = body.length.to_s
0
     end
0
     
0
+ # Write the headers
0
     headers.each { |field, value| client.write_header(field, value) }
0
- client.write("\r\n")
0
     
0
+ # Write the body
0
     if body.kind_of?(String)
0
- client.write(body)
0
- client.body_written()
0
- client.begin_transmission()
0
+ client.write_body(body)
0
     else
0
- client.begin_transmission()
0
- body.each { |p| client.write(p) }
0
- client.body_written()
0
+ body.each { |p| client.write_body(p) }
0
     end
0
+
0
   rescue => e
0
     log.puts "Ebb Error! #{e.class} #{e.message}"
0
     log.puts e.backtrace.join("\n")
0
@@ -117,8 +110,8 @@ module Ebb
0
       FFI::client_write_status(self, s, HTTP_STATUS_CODES[s])
0
     end
0
     
0
- def write(data)
0
- FFI::client_write(self, data)
0
+ def write_body(data)
0
+ FFI::client_write_body(self, data)
0
     end
0
     
0
     def write_header(field, value)
0
@@ -127,14 +120,6 @@ module Ebb
0
       end
0
     end
0
     
0
- def body_written
0
- FFI::client_set_body_written(self, true)
0
- end
0
-
0
- def begin_transmission
0
- FFI::client_begin_transmission(self)
0
- end
0
-
0
     def release
0
       FFI::client_release(self)
0
     end
...
282
283
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
286
287
...
330
331
332
333
 
334
335
 
 
 
 
 
 
336
337
338
...
520
521
522
 
523
524
525
...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
 
639
640
641
642
643
644
645
646
647
648
649
 
 
650
651
652
653
654
655
656
657
658
 
 
 
 
 
 
 
 
 
 
 
 
 
659
660
661
...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
...
382
383
384
 
385
386
387
388
389
390
391
392
393
394
395
396
...
578
579
580
581
582
583
584
...
609
610
611
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
613
614
...
635
636
637
 
 
 
 
 
 
 
 
 
 
 
638
 
639
640
641
642
 
643
 
 
 
 
 
 
644
645
646
647
 
 
 
 
 
 
 
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
0
@@ -282,6 +282,58 @@ error:
0
   ebb_client_close(client);
0
 }
0
 
0
+
0
+static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
0
+{
0
+ ebb_client *client = (ebb_client*)(watcher->data);
0
+ ssize_t sent;
0
+
0
+ if(client->status_written == FALSE || client->headers_written == FALSE) {
0
+ g_message("no status or headers - closing connection.");
0
+ goto error;
0
+ }
0
+
0
+ if(EV_ERROR & revents) {
0
+ g_message("on_client_writable() got error event, closing peer");
0
+ goto error;
0
+ }
0
+
0
+ //if(client->written != 0)
0
+ // g_debug("total written: %d", (int)(client->written));
0
+
0
+ sent = send( client->fd
0
+ , client->response_buffer->str + sizeof(gchar)*(client->written)
0
+ , client->response_buffer->len - client->written
0
+ , 0
0
+ );
0
+ if(sent < 0) {
0
+#ifdef DEBUG
0
+ g_message("Error writing: %s", strerror(errno));
0
+#endif
0
+ goto error;
0
+ } else if(sent == 0) {
0
+ /* is this the wrong thing to do? */
0
+ g_message("Sent zero bytes? Closing connection");
0
+ goto error;
0
+ }
0
+ client->written += sent;
0
+
0
+ assert(client->written <= client->response_buffer->len);
0
+ //g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
0
+
0
+ ev_timer_again(loop, &(client->timeout_watcher));
0
+
0
+ if(client->written == client->response_buffer->len) {
0
+ ev_io_stop(loop, watcher);
0
+ if(client->body_written)
0
+ ebb_client_close(client);
0
+ }
0
+ return;
0
+error:
0
+ ebb_client_close(client);
0
+}
0
+
0
+
0
 static client_init(ebb_server *server, ebb_client *client)
0
 {
0
   assert(client->in_use == FALSE);
0
@@ -330,9 +382,15 @@ static client_init(ebb_server *server, ebb_client *client)
0
   client->status_written = FALSE;
0
   client->headers_written = FALSE;
0
   client->body_written = FALSE;
0
- client->began_transmission = FALSE;
0
+ client->written = 0;
0
   
0
   /* SETUP READ AND TIMEOUT WATCHERS */
0
+ client->write_watcher.data = client;
0
+ ev_init (&client->write_watcher, on_client_writable);
0
+ ev_io_set (&client->write_watcher, client->fd, EV_WRITE | EV_ERROR);
0
+ /* Note, do not start write_watcher until there is something to be written.
0
+ * See ebb_client_write_body() */
0
+
0
   client->read_watcher.data = client;
0
   ev_init(&client->read_watcher, on_client_readable);
0
   ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
0
@@ -520,6 +578,7 @@ void ebb_client_release(ebb_client *client)
0
 {
0
   assert(client->in_use);
0
   client->in_use = FALSE;
0
+ client->body_written = TRUE;
0
   if(client->written == client->response_buffer->len)
0
     ebb_client_close(client);
0
 }
0
@@ -550,53 +609,6 @@ void ebb_client_close(ebb_client *client)
0
 }
0
 
0
 
0
-static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
0
-{
0
- ebb_client *client = (ebb_client*)(watcher->data);
0
- ssize_t sent;
0
-
0
- assert(client->status_written);
0
- assert(client->headers_written);
0
- assert(client->began_transmission);
0
-
0
- if(EV_ERROR & revents) {
0
- g_message("on_client_writable() got error event, closing peer");
0
- ebb_client_close(client);
0
- return;
0
- }
0
-
0
- //if(client->written != 0)
0
- // g_debug("total written: %d", (int)(client->written));
0
-
0
- sent = send( client->fd
0
- , client->response_buffer->str + sizeof(gchar)*(client->written)
0
- , client->response_buffer->len - client->written
0
- , 0
0
- );
0
- if(sent < 0) {
0
-#ifdef DEBUG
0
- g_message("Error writing: %s", strerror(errno));
0
-#endif
0
- ebb_client_close(client);
0
- return;
0
- } else if(sent == 0) {
0
- g_message("Sent zero bytes? Closing connection");
0
- ebb_client_close(client);
0
- }
0
- client->written += sent;
0
-
0
- assert(client->written <= client->response_buffer->len);
0
- //g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
0
-
0
- ev_timer_again(loop, &(client->timeout_watcher));
0
-
0
- if(client->written == client->response_buffer->len) {
0
- ev_io_stop(loop, watcher);
0
- if(client->body_written)
0
- ebb_client_close(client);
0
- }
0
-}
0
-
0
 void ebb_client_write_status(ebb_client *client, int status, const char *human_status)
0
 {
0
   assert(client->in_use);
0
@@ -623,39 +635,29 @@ void ebb_client_write_header(ebb_client *client, const char *field, const char *
0
                         );
0
 }
0
 
0
-void ebb_client_write(ebb_client *client, const char *data, int length)
0
-{
0
- assert(client->in_use);
0
- if(!client->open) return;
0
- g_string_append_len(client->response_buffer, data, length);
0
- if(client->began_transmission) {
0
- /* restart the watcher if we're streaming */
0
- ev_io_start(client->server->loop, &client->write_watcher);
0
- }
0
-}
0
-
0
 
0
-void ebb_client_begin_transmission(ebb_client *client)
0
+void ebb_client_write_body(ebb_client *client, const char *data, int length)
0
 {
0
   assert(client->in_use);
0
   if(!client->open) return;
0
- assert(FALSE == ev_is_active(&client->write_watcher));
0
   
0
- /* assure the socket is still in non-blocking mode */
0
- int flags = fcntl(client->fd, F_GETFL, 0);
0
- if(0 > fcntl(client->fd, F_SETFL, flags | O_NONBLOCK)) {
0
- perror("fcntl()");
0
- ebb_client_close(client);
0
- return;
0
+ if(client->headers_written == FALSE) {
0
+ g_string_append(client->response_buffer, "\r\n");
0
   }
0
   
0
- client->headers_written = TRUE;
0
- client->began_transmission = TRUE;
0
- client->written = 0;
0
- client->write_watcher.data = client;
0
- ev_init (&(client->write_watcher), on_client_writable);
0
- ev_io_set (&(client->write_watcher), client->fd, EV_WRITE | EV_ERROR);
0
- ev_io_start(client->server->loop, &client->write_watcher);
0
+ g_string_append_len(client->response_buffer, data, length);
0
+
0
+ /* If the write_watcher isn't yet active, then start it. It could be that
0
+ * we're streaming and the watcher has been stopped. In that case we
0
+ * start it again since we have more to write. */
0
+ if(ev_is_active(&client->write_watcher) == FALSE) {
0
+ /* assure the socket is still in non-blocking mode */
0
+ int flags = fcntl(client->fd, F_GETFL, 0);
0
+ if(0 > fcntl(client->fd, F_SETFL, flags | O_NONBLOCK))
0
+ perror("fcntl() setting non-block");
0
+ client->headers_written = TRUE;
0
+ ev_io_start(client->server->loop, &client->write_watcher);
0
+ }
0
 }
0
 
0
 
...
15
16
17
18
 
19
20
21
...
30
31
32
33
 
 
34
35
36
...
76
77
78
79
80
81
82
...
15
16
17
 
18
19
20
21
...
30
31
32
 
33
34
35
36
37
...
77
78
79
 
80
81
82
0
@@ -15,7 +15,7 @@ typedef struct ebb_server ebb_server;
0
 typedef struct ebb_client ebb_client;
0
 #define EBB_VERSION "0.1.0"
0
 #define EBB_BUFFERSIZE (1024 * (80 + 33))
0
-#define EBB_MAX_CLIENTS 200
0
+#define EBB_MAX_CLIENTS 1024
0
 #define EBB_TIMEOUT 30.0
0
 #define EBB_MAX_ENV 500
0
 #define EBB_TCP_COMMON \
0
@@ -30,7 +30,8 @@ void ebb_client_release(ebb_client*);
0
 int ebb_client_read(ebb_client *client, char *buffer, int length);
0
 void ebb_client_write_status(ebb_client*, int status, const char *human_status);
0
 void ebb_client_write_header(ebb_client*, const char *field, const char *value);
0
-void ebb_client_write(ebb_client*, const char *data, int length);
0
+void ebb_client_write_body(ebb_client*, const char *data, int length);
0
+
0
 void ebb_client_begin_transmission( ebb_client *client);
0
 
0
 struct ebb_env_item {
0
@@ -76,7 +77,6 @@ struct ebb_client {
0
   unsigned int status_written : 1;
0
   unsigned int headers_written : 1;
0
   unsigned int body_written : 1;
0
- unsigned int began_transmission : 1;
0
   
0
   /* the ENV structure */
0
   int env_size;
...
213
214
215
216
 
217
218
219
220
 
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
280
281
282
283
284
285
 
286
287
288
...
213
214
215
 
216
217
218
219
 
220
221
222
223
224
 
 
 
 
 
 
 
 
 
 
225
226
227
...
231
232
233
 
 
 
 
 
 
 
 
234
235
236
...
262
263
264
 
 
 
265
266
267
268
0
@@ -213,25 +213,15 @@ VALUE client_write_header(VALUE _, VALUE client, VALUE field, VALUE value)
0
   return Qnil;
0
 }
0
 
0
-VALUE client_write(VALUE _, VALUE client, VALUE string)
0
+VALUE client_write_body(VALUE _, VALUE client, VALUE string)
0
 {
0
   ebb_client *_client;
0
   Data_Get_Struct(client, ebb_client, _client);
0
- ebb_client_write(_client, RSTRING_PTR(string), RSTRING_LEN(string));
0
+ ebb_client_write_body(_client, RSTRING_PTR(string), RSTRING_LEN(string));
0
   return Qnil;
0
 }
0
 
0
 
0
-VALUE client_begin_transmission(VALUE _, VALUE rb_client)
0
-{
0
- ebb_client *client;
0
- Data_Get_Struct(rb_client, ebb_client, client);
0
- client->status_written = TRUE;
0
- client->headers_written = TRUE;
0
- ebb_client_begin_transmission(client);
0
- return Qnil;
0
-}
0
-
0
 VALUE client_release(VALUE _, VALUE rb_client)
0
 {
0
   ebb_client *client;
0
@@ -241,14 +231,6 @@ VALUE client_release(VALUE _, VALUE rb_client)
0
 }
0
 
0
 
0
-VALUE client_set_body_written(VALUE _, VALUE rb_client, VALUE v)
0
-{
0
- ebb_client *client;
0
- Data_Get_Struct(rb_client, ebb_client, client);
0
- client->body_written = RTEST(v);
0
- return client->body_written ? Qtrue : Qfalse;
0
-}
0
-
0
 void Init_ebb_ext()
0
 {
0
   VALUE mEbb = rb_define_module("Ebb");
0
@@ -280,9 +262,7 @@ void Init_ebb_ext()
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", client_write, 2);
0
- rb_define_singleton_method(mFFI, "client_begin_transmission", client_begin_transmission, 1);
0
- rb_define_singleton_method(mFFI, "client_set_body_written", client_set_body_written, 2);
0
+ rb_define_singleton_method(mFFI, "client_write_body", client_write_body, 2);
0
   rb_define_singleton_method(mFFI, "client_env", client_env, 1);
0
   rb_define_singleton_method(mFFI, "client_release", client_release, 1);
0
   

Comments

    No one has commented yet.