em-http-request 0.3.0 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of em-http-request might be problematic. Click here for more details.

Files changed (44) hide show
  1. data/.gitignore +1 -0
  2. data/Changelog.md +10 -0
  3. data/README.md +43 -160
  4. data/Rakefile +2 -73
  5. data/em-http-request.gemspec +7 -7
  6. data/examples/fetch.rb +30 -30
  7. data/examples/fibered-http.rb +38 -38
  8. data/examples/oauth-tweet.rb +49 -49
  9. data/lib/em-http.rb +4 -6
  10. data/lib/em-http/client.rb +101 -522
  11. data/lib/em-http/http_connection.rb +125 -0
  12. data/lib/em-http/http_encoding.rb +19 -12
  13. data/lib/em-http/http_header.rb +2 -17
  14. data/lib/em-http/http_options.rb +37 -19
  15. data/lib/em-http/request.rb +33 -66
  16. data/lib/em-http/version.rb +2 -2
  17. data/spec/client_spec.rb +575 -0
  18. data/spec/dns_spec.rb +41 -0
  19. data/spec/encoding_spec.rb +6 -6
  20. data/spec/external_spec.rb +99 -0
  21. data/spec/fixtures/google.ca +13 -17
  22. data/spec/helper.rb +17 -8
  23. data/spec/http_proxy_spec.rb +53 -0
  24. data/spec/middleware_spec.rb +114 -0
  25. data/spec/multi_spec.rb +11 -38
  26. data/spec/pipelining_spec.rb +38 -0
  27. data/spec/redirect_spec.rb +114 -0
  28. data/spec/socksify_proxy_spec.rb +24 -0
  29. data/spec/ssl_spec.rb +20 -0
  30. data/spec/stallion.rb +7 -63
  31. metadata +59 -39
  32. data/examples/websocket-handler.rb +0 -28
  33. data/examples/websocket-server.rb +0 -8
  34. data/ext/buffer/em_buffer.c +0 -639
  35. data/ext/buffer/extconf.rb +0 -53
  36. data/ext/http11_client/ext_help.h +0 -14
  37. data/ext/http11_client/extconf.rb +0 -6
  38. data/ext/http11_client/http11_client.c +0 -328
  39. data/ext/http11_client/http11_parser.c +0 -418
  40. data/ext/http11_client/http11_parser.h +0 -48
  41. data/ext/http11_client/http11_parser.rl +0 -170
  42. data/lib/em-http/mock.rb +0 -137
  43. data/spec/mock_spec.rb +0 -166
  44. data/spec/request_spec.rb +0 -1003
@@ -1,28 +0,0 @@
1
- require 'rubygems'
2
- require 'lib/em-http'
3
-
4
- module KBHandler
5
- include EM::Protocols::LineText2
6
-
7
- def receive_line(data)
8
- p "Want to send: #{data}"
9
- p "Error status: #{$http.error?}"
10
- $http.send(data)
11
- p "After send"
12
- end
13
- end
14
-
15
- EventMachine.run {
16
- $http = EventMachine::HttpRequest.new("ws://localhost:8080/").get :timeout => 0
17
-
18
- $http.disconnect { puts 'oops' }
19
- $http.callback {
20
- puts "WebSocket connected!"
21
- }
22
-
23
- $http.stream { |msg|
24
- puts "Recieved: #{msg}"
25
- }
26
-
27
- EM.open_keyboard(KBHandler)
28
- }
@@ -1,8 +0,0 @@
1
- require 'rubygems'
2
- require 'em-websocket'
3
-
4
- EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
5
- ws.onopen { ws.send "Hello Client!"}
6
- ws.onmessage { |msg| p "got: #{msg}"; ws.send "Pong: #{msg}" }
7
- ws.onclose { puts "WebSocket closed" }
8
- end
@@ -1,639 +0,0 @@
1
- /*
2
- * Copyright (C) 2007 Tony Arcieri
3
- * You may redistribute this under the terms of the Ruby license.
4
- * See LICENSE for details
5
- */
6
-
7
- #include "ruby.h"
8
- #include "rubyio.h"
9
-
10
- #include <assert.h>
11
-
12
- #include <string.h>
13
- #include <time.h>
14
- #include <errno.h>
15
-
16
- #ifndef GetReadFile
17
- #define FPTR_TO_FD(fptr) (fptr->fd)
18
- #else
19
- #define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
20
- #endif
21
-
22
- /* Default number of bytes in each node's buffer */
23
- #define DEFAULT_NODE_SIZE 16384
24
-
25
- /* Maximum age of a buffer node in a memory pool, in seconds */
26
- #define MAX_AGE 60
27
-
28
- /* How often to scan the pool for old nodes */
29
- #define PURGE_INTERVAL 10
30
-
31
- struct buffer {
32
- time_t last_purged_at;
33
- unsigned size, node_size;
34
- struct buffer_node *head, *tail;
35
- struct buffer_node *pool_head, *pool_tail;
36
-
37
- };
38
-
39
- struct buffer_node {
40
- time_t last_used_at;
41
- unsigned start, end;
42
- struct buffer_node *next;
43
- unsigned char data[0];
44
- };
45
-
46
- static VALUE mEm = Qnil;
47
- static VALUE cEm_Buffer = Qnil;
48
-
49
- static VALUE Em_Buffer_allocate(VALUE klass);
50
- static void Em_Buffer_mark(struct buffer *);
51
- static void Em_Buffer_free(struct buffer *);
52
-
53
- static VALUE Em_Buffer_initialize(int argc, VALUE *argv, VALUE self);
54
- static VALUE Em_Buffer_clear(VALUE self);
55
- static VALUE Em_Buffer_size(VALUE self);
56
- static VALUE Em_Buffer_empty(VALUE self);
57
- static VALUE Em_Buffer_append(VALUE self, VALUE data);
58
- static VALUE Em_Buffer_prepend(VALUE self, VALUE data);
59
- static VALUE Em_Buffer_read(int argc, VALUE *argv, VALUE self);
60
- static VALUE Em_Buffer_to_str(VALUE self);
61
- static VALUE Em_Buffer_read_from(VALUE self, VALUE io);
62
- static VALUE Em_Buffer_write_to(VALUE self, VALUE io);
63
-
64
- static struct buffer *buffer_new(void);
65
- static void buffer_clear(struct buffer *buf);
66
- static void buffer_free(struct buffer *buf);
67
- static void buffer_gc(struct buffer *buf);
68
- static void buffer_prepend(struct buffer *buf, char *str, unsigned len);
69
- static void buffer_append(struct buffer *buf, char *str, unsigned len);
70
- static void buffer_read(struct buffer *buf, char *str, unsigned len);
71
- static void buffer_copy(struct buffer *buf, char *str, unsigned len);
72
- static int buffer_read_from(struct buffer *buf, int fd);
73
- static int buffer_write_to(struct buffer *buf, int fd);
74
-
75
- /*
76
- * High speed buffering geared towards non-blocking I/O.
77
- *
78
- * Data is stored in a byte queue implemented as a linked list of equal size
79
- * chunks. Since every node in the list is the same size they are easily
80
- * memory pooled. Routines are provided for high speed non-blocking reads
81
- * and writes from Ruby IO objects.
82
- */
83
- void Init_em_buffer()
84
- {
85
- mEm = rb_define_module("EventMachine");
86
- cEm_Buffer = rb_define_class_under(mEm, "Buffer", rb_cObject);
87
- rb_define_alloc_func(cEm_Buffer, Em_Buffer_allocate);
88
-
89
- rb_define_method(cEm_Buffer, "initialize", Em_Buffer_initialize, -1);
90
- rb_define_method(cEm_Buffer, "clear", Em_Buffer_clear, 0);
91
- rb_define_method(cEm_Buffer, "size", Em_Buffer_size, 0);
92
- rb_define_method(cEm_Buffer, "empty?", Em_Buffer_empty, 0);
93
- rb_define_method(cEm_Buffer, "<<", Em_Buffer_append, 1);
94
- rb_define_method(cEm_Buffer, "append", Em_Buffer_append, 1);
95
- rb_define_method(cEm_Buffer, "prepend", Em_Buffer_prepend, 1);
96
- rb_define_method(cEm_Buffer, "read", Em_Buffer_read, -1);
97
- rb_define_method(cEm_Buffer, "to_str", Em_Buffer_to_str, 0);
98
- rb_define_method(cEm_Buffer, "read_from", Em_Buffer_read_from, 1);
99
- rb_define_method(cEm_Buffer, "write_to", Em_Buffer_write_to, 1);
100
- }
101
-
102
- static VALUE Em_Buffer_allocate(VALUE klass)
103
- {
104
- return Data_Wrap_Struct(klass, Em_Buffer_mark, Em_Buffer_free, buffer_new());
105
- }
106
-
107
- static void Em_Buffer_mark(struct buffer *buf)
108
- {
109
- /* Walks the pool of unused chunks and frees any that are beyond a certain age */
110
- buffer_gc(buf);
111
- }
112
-
113
- static void Em_Buffer_free(struct buffer *buf)
114
- {
115
- buffer_free(buf);
116
- }
117
-
118
- /**
119
- * call-seq:
120
- * EventMachine::Buffer.new(size = DEFAULT_NODE_SIZE) -> EventMachine::Buffer
121
- *
122
- * Create a new EventMachine::Buffer with linked segments of the given size
123
- */
124
- static VALUE Em_Buffer_initialize(int argc, VALUE *argv, VALUE self)
125
- {
126
- VALUE node_size_obj;
127
- int node_size;
128
- struct buffer *buf;
129
-
130
- if(rb_scan_args(argc, argv, "01", &node_size_obj) == 1) {
131
- node_size = NUM2INT(node_size_obj);
132
-
133
- if(node_size < 1) rb_raise(rb_eArgError, "invalid buffer size");
134
-
135
- Data_Get_Struct(self, struct buffer, buf);
136
-
137
- /* Make sure we're not changing the buffer size after data has been allocated */
138
- assert(!buf->head);
139
- assert(!buf->pool_head);
140
-
141
- buf->node_size = node_size;
142
- }
143
-
144
- return Qnil;
145
- }
146
-
147
- /**
148
- * call-seq:
149
- * EventMachine::Buffer#clear -> nil
150
- *
151
- * Clear all data from the EventMachine::Buffer
152
- */
153
- static VALUE Em_Buffer_clear(VALUE self)
154
- {
155
- struct buffer *buf;
156
- Data_Get_Struct(self, struct buffer, buf);
157
-
158
- buffer_clear(buf);
159
-
160
- return Qnil;
161
- }
162
-
163
- /**
164
- * call-seq:
165
- * EventMachine::Buffer#size -> Integer
166
- *
167
- * Return the size of the buffer in bytes
168
- */
169
- static VALUE Em_Buffer_size(VALUE self)
170
- {
171
- struct buffer *buf;
172
- Data_Get_Struct(self, struct buffer, buf);
173
-
174
- return INT2NUM(buf->size);
175
- }
176
-
177
- /**
178
- * call-seq:
179
- * EventMachine::Buffer#empty? -> Boolean
180
- *
181
- * Is the buffer empty?
182
- */
183
- static VALUE Em_Buffer_empty(VALUE self)
184
- {
185
- struct buffer *buf;
186
- Data_Get_Struct(self, struct buffer, buf);
187
-
188
- return buf->size > 0 ? Qfalse : Qtrue;
189
- }
190
-
191
- /**
192
- * call-seq:
193
- * EventMachine::Buffer#append(data) -> String
194
- *
195
- * Append the given data to the end of the buffer
196
- */
197
- static VALUE Em_Buffer_append(VALUE self, VALUE data)
198
- {
199
- struct buffer *buf;
200
- Data_Get_Struct(self, struct buffer, buf);
201
-
202
- /* Is this needed? Never seen anyone else do it... */
203
- data = rb_convert_type(data, T_STRING, "String", "to_str");
204
- buffer_append(buf, RSTRING_PTR(data), RSTRING_LEN(data));
205
-
206
- return data;
207
- }
208
-
209
- /**
210
- * call-seq:
211
- * EventMachine::Buffer#prepend(data) -> String
212
- *
213
- * Prepend the given data to the beginning of the buffer
214
- */
215
- static VALUE Em_Buffer_prepend(VALUE self, VALUE data)
216
- {
217
- struct buffer *buf;
218
- Data_Get_Struct(self, struct buffer, buf);
219
-
220
- data = rb_convert_type(data, T_STRING, "String", "to_str");
221
- buffer_prepend(buf, RSTRING_PTR(data), RSTRING_LEN(data));
222
-
223
- return data;
224
- }
225
-
226
- /**
227
- * call-seq:
228
- * EventMachine::Buffer#read(length = nil) -> String
229
- *
230
- * Read the specified abount of data from the buffer. If no value
231
- * is given the entire contents of the buffer are returned. Any data
232
- * read from the buffer is cleared.
233
- */
234
- static VALUE Em_Buffer_read(int argc, VALUE *argv, VALUE self)
235
- {
236
- VALUE length_obj, str;
237
- int length;
238
- struct buffer *buf;
239
-
240
- Data_Get_Struct(self, struct buffer, buf);
241
-
242
- if(rb_scan_args(argc, argv, "01", &length_obj) == 1) {
243
- length = NUM2INT(length_obj);
244
- } else {
245
- if(buf->size == 0)
246
- return rb_str_new2("");
247
-
248
- length = buf->size;
249
- }
250
-
251
- if(length > buf->size)
252
- length = buf->size;
253
-
254
- if(length < 1)
255
- rb_raise(rb_eArgError, "length must be greater than zero");
256
-
257
- str = rb_str_new(0, length);
258
- buffer_read(buf, RSTRING_PTR(str), length);
259
-
260
- return str;
261
- }
262
-
263
- /**
264
- * call-seq:
265
- * EventMachine::Buffer#to_str -> String
266
- *
267
- * Convert the Buffer to a String. The original buffer is unmodified.
268
- */
269
- static VALUE Em_Buffer_to_str(VALUE self) {
270
- VALUE str;
271
- struct buffer *buf;
272
-
273
- Data_Get_Struct(self, struct buffer, buf);
274
-
275
- str = rb_str_new(0, buf->size);
276
- buffer_copy(buf, RSTRING_PTR(str), buf->size);
277
-
278
- return str;
279
- }
280
-
281
- /**
282
- * call-seq:
283
- * EventMachine::Buffer#read_from(io) -> Integer
284
- *
285
- * Perform a nonblocking read of the the given IO object and fill
286
- * the buffer with any data received. The call will read as much
287
- * data as it can until the read would block.
288
- */
289
- static VALUE Em_Buffer_read_from(VALUE self, VALUE io) {
290
- struct buffer *buf;
291
- #if HAVE_RB_IO_T
292
- rb_io_t *fptr;
293
- #else
294
- OpenFile *fptr;
295
- #endif
296
-
297
- Data_Get_Struct(self, struct buffer, buf);
298
- GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
299
- rb_io_set_nonblock(fptr);
300
-
301
- #ifdef HAVE_RB_IO_FD
302
- return INT2NUM(buffer_read_from(buf, rb_io_fd(io)));
303
- #else
304
- return INT2NUM(buffer_read_from(buf, FPTR_TO_FD(fptr)));
305
- #endif
306
- }
307
-
308
- /**
309
- * call-seq:
310
- * EventMachine::Buffer#write_to(io) -> Integer
311
- *
312
- * Perform a nonblocking write of the buffer to the given IO object.
313
- * As much data as possible is written until the call would block.
314
- * Any data which is written is removed from the buffer.
315
- */
316
- static VALUE Em_Buffer_write_to(VALUE self, VALUE io) {
317
- struct buffer *buf;
318
- #if HAVE_RB_IO_T
319
- rb_io_t *fptr;
320
- #else
321
- OpenFile *fptr;
322
- #endif
323
-
324
- Data_Get_Struct(self, struct buffer, buf);
325
- GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
326
- rb_io_set_nonblock(fptr);
327
-
328
- #ifdef HAVE_RB_IO_FD
329
- return INT2NUM(buffer_read_from(buf, rb_io_fd(io)));
330
- #else
331
- return INT2NUM(buffer_read_from(buf, FPTR_TO_FD(fptr)));
332
- #endif
333
-
334
- }
335
-
336
- /*
337
- * Ruby bindings end here. Below is the actual implementation of
338
- * the underlying data structures.
339
- */
340
-
341
- /* Create a new buffer */
342
- static struct buffer *buffer_new(void)
343
- {
344
- struct buffer *buf;
345
-
346
- buf = (struct buffer *)xmalloc(sizeof(struct buffer));
347
- buf->head = buf->tail = buf->pool_head = buf->pool_tail = 0;
348
- buf->size = 0;
349
- buf->node_size = DEFAULT_NODE_SIZE;
350
- time(&buf->last_purged_at);
351
-
352
- return buf;
353
- }
354
-
355
- /* Clear all data from a buffer */
356
- static void buffer_clear(struct buffer *buf)
357
- {
358
- struct buffer_node *tmp;
359
-
360
- /* Move everything into the buffer pool */
361
- if(!buf->pool_tail)
362
- buf->pool_head = buf->pool_tail = buf->head;
363
- else
364
- buf->pool_tail->next = buf->head;
365
-
366
- buf->head = buf->tail = 0;
367
- buf->size = 0;
368
- }
369
-
370
- /* Free a buffer */
371
- static void buffer_free(struct buffer *buf)
372
- {
373
- struct buffer_node *tmp;
374
-
375
- buffer_clear(buf);
376
-
377
- while(buf->pool_head) {
378
- tmp = buf->pool_head;
379
- buf->pool_head = tmp->next;
380
- free(tmp);
381
- }
382
-
383
- free(buf);
384
- }
385
-
386
- /* Run through the pool and find elements that haven't been used for awhile */
387
- static void buffer_gc(struct buffer *buf)
388
- {
389
- struct buffer_node *cur, *tmp;
390
- time_t now;
391
- time(&now);
392
-
393
- /* Only purge if we've passed the purge interval */
394
- if(now - buf->last_purged_at < PURGE_INTERVAL)
395
- return;
396
-
397
- buf->last_purged_at = now;
398
-
399
- while(buf->pool_head && now - buf->pool_head->last_used_at >= MAX_AGE) {
400
- tmp = buf->pool_head;
401
- buf->pool_head = buf->pool_head->next;
402
- free(tmp);
403
- }
404
-
405
- if(!buf->pool_head)
406
- buf->pool_tail = 0;
407
- }
408
-
409
- /* Create a new buffer_node (or pull one from the memory pool) */
410
- static struct buffer_node *buffer_node_new(struct buffer *buf)
411
- {
412
- struct buffer_node *node;
413
-
414
- /* Pull from the memory pool if available */
415
- if(buf->pool_head) {
416
- node = buf->pool_head;
417
- buf->pool_head = node->next;
418
-
419
- if(node->next)
420
- node->next = 0;
421
- else
422
- buf->pool_tail = 0;
423
- } else {
424
- node = (struct buffer_node *)xmalloc(sizeof(struct buffer_node) + buf->node_size);
425
- node->next = 0;
426
- }
427
-
428
- node->start = node->end = 0;
429
- return node;
430
- }
431
-
432
- /* Free a buffer node (i.e. return it to the memory pool) */
433
- static void buffer_node_free(struct buffer *buf, struct buffer_node *node)
434
- {
435
- /* Store when the node was freed */
436
- time(&node->last_used_at);
437
-
438
- node->next = buf->pool_head;
439
- buf->pool_head = node;
440
-
441
- if(!buf->pool_tail)
442
- buf->pool_tail = node;
443
- }
444
-
445
- /* Prepend data to the front of the buffer */
446
- static void buffer_prepend(struct buffer *buf, char *str, unsigned len)
447
- {
448
- struct buffer_node *node, *tmp;
449
- buf->size += len;
450
-
451
- /* If it fits in the beginning of the head */
452
- if(buf->head && buf->head->start >= len) {
453
- buf->head->start -= len;
454
- memcpy(buf->head->data + buf->head->start, str, len);
455
- } else {
456
- node = buffer_node_new(buf);
457
- node->next = buf->head;
458
- buf->head = node;
459
- if(!buf->tail) buf->tail = node;
460
-
461
- while(len > buf->node_size) {
462
- memcpy(node->data, str, buf->node_size);
463
- node->end = buf->node_size;
464
-
465
- tmp = buffer_node_new(buf);
466
- tmp->next = node->next;
467
- node->next = tmp;
468
-
469
- if(buf->tail == node) buf->tail = tmp;
470
- node = tmp;
471
-
472
- str += buf->node_size;
473
- len -= buf->node_size;
474
- }
475
-
476
- if(len > 0) {
477
- memcpy(node->data, str, len);
478
- node->end = len;
479
- }
480
- }
481
- }
482
-
483
- /* Append data to the front of the buffer */
484
- static void buffer_append(struct buffer *buf, char *str, unsigned len)
485
- {
486
- unsigned nbytes;
487
- buf->size += len;
488
-
489
- /* If it fits in the remaining space in the tail */
490
- if(buf->tail && len <= buf->node_size - buf->tail->end) {
491
- memcpy(buf->tail->data + buf->tail->end, str, len);
492
- buf->tail->end += len;
493
- return;
494
- }
495
-
496
- /* Empty list needs initialized */
497
- if(!buf->head) {
498
- buf->head = buffer_node_new(buf);
499
- buf->tail = buf->head;
500
- }
501
-
502
- /* Build links out of the data */
503
- while(len > 0) {
504
- nbytes = buf->node_size - buf->tail->end;
505
- if(len < nbytes) nbytes = len;
506
-
507
- memcpy(buf->tail->data + buf->tail->end, str, nbytes);
508
- str += nbytes;
509
- len -= nbytes;
510
-
511
- buf->tail->end += nbytes;
512
-
513
- if(len > 0) {
514
- buf->tail->next = buffer_node_new(buf);
515
- buf->tail = buf->tail->next;
516
- }
517
- }
518
- }
519
-
520
- /* Read data from the buffer (and clear what we've read) */
521
- static void buffer_read(struct buffer *buf, char *str, unsigned len)
522
- {
523
- unsigned nbytes;
524
- struct buffer_node *tmp;
525
-
526
- while(buf->size > 0 && len > 0) {
527
- nbytes = buf->head->end - buf->head->start;
528
- if(len < nbytes) nbytes = len;
529
-
530
- memcpy(str, buf->head->data + buf->head->start, nbytes);
531
- str += nbytes;
532
- len -= nbytes;
533
-
534
- buf->head->start += nbytes;
535
- buf->size -= nbytes;
536
-
537
- if(buf->head->start == buf->head->end) {
538
- tmp = buf->head;
539
- buf->head = tmp->next;
540
- buffer_node_free(buf, tmp);
541
-
542
- if(!buf->head) buf->tail = 0;
543
- }
544
- }
545
- }
546
-
547
- /* Copy data from the buffer without clearing it */
548
- static void buffer_copy(struct buffer *buf, char *str, unsigned len)
549
- {
550
- unsigned nbytes;
551
- struct buffer_node *node;
552
-
553
- node = buf->head;
554
- while(node && len > 0) {
555
- nbytes = node->end - node->start;
556
- if(len < nbytes) nbytes = len;
557
-
558
- memcpy(str, node->data + node->start, nbytes);
559
- str += nbytes;
560
- len -= nbytes;
561
-
562
- if(node->start + nbytes == node->end)
563
- node = node->next;
564
- }
565
- }
566
-
567
- /* Write data from the buffer to a file descriptor */
568
- static int buffer_write_to(struct buffer *buf, int fd)
569
- {
570
- int bytes_written, total_bytes_written = 0;
571
- struct buffer_node *tmp;
572
-
573
- while(buf->head) {
574
- bytes_written = write(fd, buf->head->data + buf->head->start, buf->head->end - buf->head->start);
575
-
576
- /* If the write failed... */
577
- if(bytes_written < 0) {
578
- if(errno != EAGAIN)
579
- rb_sys_fail("write");
580
-
581
- return total_bytes_written;
582
- }
583
-
584
- total_bytes_written += bytes_written;
585
- buf->size -= bytes_written;
586
-
587
- /* If the write blocked... */
588
- if(bytes_written < buf->head->end - buf->head->start) {
589
- buf->head->start += bytes_written;
590
- return total_bytes_written;
591
- }
592
-
593
- /* Otherwise we wrote the whole buffer */
594
- tmp = buf->head;
595
- buf->head = tmp->next;
596
- buffer_node_free(buf, tmp);
597
-
598
- if(!buf->head) buf->tail = 0;
599
- }
600
-
601
- return total_bytes_written;
602
- }
603
-
604
- /* Read data from a file descriptor to a buffer */
605
- /* Append data to the front of the buffer */
606
- static int buffer_read_from(struct buffer *buf, int fd)
607
- {
608
- int bytes_read, total_bytes_read = 0;
609
- unsigned nbytes;
610
-
611
- /* Empty list needs initialized */
612
- if(!buf->head) {
613
- buf->head = buffer_node_new(buf);
614
- buf->tail = buf->head;
615
- }
616
-
617
- do {
618
- nbytes = buf->node_size - buf->tail->end;
619
- bytes_read = read(fd, buf->tail->data + buf->tail->end, nbytes);
620
-
621
- if(bytes_read < 1) {
622
- if(errno != EAGAIN)
623
- rb_sys_fail("read");
624
-
625
- return total_bytes_read;
626
- }
627
-
628
- total_bytes_read += bytes_read;
629
- buf->tail->end += nbytes;
630
- buf->size += nbytes;
631
-
632
- if(buf->tail->end == buf->node_size) {
633
- buf->tail->next = buffer_node_new(buf);
634
- buf->tail = buf->tail->next;
635
- }
636
- } while(bytes_read == nbytes);
637
-
638
- return total_bytes_read;
639
- }