rfuzz 0.6

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.
Files changed (136) hide show
  1. data/COPYING +55 -0
  2. data/LICENSE +55 -0
  3. data/README +252 -0
  4. data/Rakefile +48 -0
  5. data/doc/rdoc/classes/RFuzz.html +146 -0
  6. data/doc/rdoc/classes/RFuzz/HttpClient.html +481 -0
  7. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000010.html +24 -0
  8. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000011.html +34 -0
  9. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000012.html +49 -0
  10. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000013.html +49 -0
  11. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000014.html +57 -0
  12. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000015.html +37 -0
  13. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000016.html +26 -0
  14. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000017.html +34 -0
  15. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000018.html +18 -0
  16. data/doc/rdoc/classes/RFuzz/HttpClient.src/M000019.html +26 -0
  17. data/doc/rdoc/classes/RFuzz/HttpEncoding.html +294 -0
  18. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000001.html +26 -0
  19. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000002.html +18 -0
  20. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000003.html +26 -0
  21. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000004.html +18 -0
  22. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000005.html +32 -0
  23. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000006.html +18 -0
  24. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000007.html +20 -0
  25. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000008.html +20 -0
  26. data/doc/rdoc/classes/RFuzz/HttpEncoding.src/M000009.html +32 -0
  27. data/doc/rdoc/classes/RFuzz/HttpResponse.html +180 -0
  28. data/doc/rdoc/classes/RFuzz/Notifier.html +252 -0
  29. data/doc/rdoc/classes/RFuzz/Notifier.src/M000044.html +17 -0
  30. data/doc/rdoc/classes/RFuzz/Notifier.src/M000045.html +17 -0
  31. data/doc/rdoc/classes/RFuzz/Notifier.src/M000046.html +17 -0
  32. data/doc/rdoc/classes/RFuzz/Notifier.src/M000047.html +17 -0
  33. data/doc/rdoc/classes/RFuzz/Notifier.src/M000048.html +17 -0
  34. data/doc/rdoc/classes/RFuzz/Notifier.src/M000049.html +17 -0
  35. data/doc/rdoc/classes/RFuzz/RandomGenerator.html +362 -0
  36. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000032.html +21 -0
  37. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000033.html +23 -0
  38. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000036.html +22 -0
  39. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000037.html +20 -0
  40. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000038.html +22 -0
  41. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000039.html +20 -0
  42. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000040.html +18 -0
  43. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000041.html +18 -0
  44. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000042.html +22 -0
  45. data/doc/rdoc/classes/RFuzz/RandomGenerator.src/M000043.html +18 -0
  46. data/doc/rdoc/classes/RFuzz/Sampler.html +383 -0
  47. data/doc/rdoc/classes/RFuzz/Sampler.src/M000056.html +19 -0
  48. data/doc/rdoc/classes/RFuzz/Sampler.src/M000057.html +23 -0
  49. data/doc/rdoc/classes/RFuzz/Sampler.src/M000058.html +26 -0
  50. data/doc/rdoc/classes/RFuzz/Sampler.src/M000059.html +18 -0
  51. data/doc/rdoc/classes/RFuzz/Sampler.src/M000060.html +18 -0
  52. data/doc/rdoc/classes/RFuzz/Sampler.src/M000061.html +18 -0
  53. data/doc/rdoc/classes/RFuzz/Sampler.src/M000062.html +18 -0
  54. data/doc/rdoc/classes/RFuzz/Sampler.src/M000063.html +19 -0
  55. data/doc/rdoc/classes/RFuzz/Sampler.src/M000064.html +18 -0
  56. data/doc/rdoc/classes/RFuzz/Sampler.src/M000065.html +23 -0
  57. data/doc/rdoc/classes/RFuzz/Sampler.src/M000066.html +18 -0
  58. data/doc/rdoc/classes/RFuzz/Sampler.src/M000067.html +20 -0
  59. data/doc/rdoc/classes/RFuzz/Session.html +415 -0
  60. data/doc/rdoc/classes/RFuzz/Session.src/M000020.html +31 -0
  61. data/doc/rdoc/classes/RFuzz/Session.src/M000021.html +18 -0
  62. data/doc/rdoc/classes/RFuzz/Session.src/M000022.html +18 -0
  63. data/doc/rdoc/classes/RFuzz/Session.src/M000023.html +34 -0
  64. data/doc/rdoc/classes/RFuzz/Session.src/M000024.html +19 -0
  65. data/doc/rdoc/classes/RFuzz/Session.src/M000025.html +19 -0
  66. data/doc/rdoc/classes/RFuzz/Session.src/M000026.html +26 -0
  67. data/doc/rdoc/classes/RFuzz/Session.src/M000027.html +29 -0
  68. data/doc/rdoc/classes/RFuzz/Session.src/M000028.html +19 -0
  69. data/doc/rdoc/classes/RFuzz/Session.src/M000029.html +18 -0
  70. data/doc/rdoc/classes/RFuzz/Session.src/M000030.html +18 -0
  71. data/doc/rdoc/classes/RFuzz/Session.src/M000031.html +23 -0
  72. data/doc/rdoc/classes/RFuzz/StatsTracker.html +242 -0
  73. data/doc/rdoc/classes/RFuzz/StatsTracker.src/M000050.html +19 -0
  74. data/doc/rdoc/classes/RFuzz/StatsTracker.src/M000051.html +19 -0
  75. data/doc/rdoc/classes/RFuzz/StatsTracker.src/M000052.html +18 -0
  76. data/doc/rdoc/classes/RFuzz/StatsTracker.src/M000053.html +18 -0
  77. data/doc/rdoc/classes/RFuzz/StatsTracker.src/M000054.html +28 -0
  78. data/doc/rdoc/classes/RFuzz/StatsTracker.src/M000055.html +18 -0
  79. data/doc/rdoc/created.rid +1 -0
  80. data/doc/rdoc/files/COPYING.html +168 -0
  81. data/doc/rdoc/files/LICENSE.html +168 -0
  82. data/doc/rdoc/files/README.html +473 -0
  83. data/doc/rdoc/files/lib/rfuzz/client_rb.html +111 -0
  84. data/doc/rdoc/files/lib/rfuzz/random_rb.html +116 -0
  85. data/doc/rdoc/files/lib/rfuzz/rfuzz_rb.html +109 -0
  86. data/doc/rdoc/files/lib/rfuzz/session_rb.html +111 -0
  87. data/doc/rdoc/files/lib/rfuzz/stats_rb.html +113 -0
  88. data/doc/rdoc/fr_class_index.html +35 -0
  89. data/doc/rdoc/fr_file_index.html +34 -0
  90. data/doc/rdoc/fr_method_index.html +93 -0
  91. data/doc/rdoc/index.html +24 -0
  92. data/doc/rdoc/rdoc-style.css +208 -0
  93. data/examples/amazon_headers.rb +38 -0
  94. data/examples/hpricot_pudding.rb +22 -0
  95. data/examples/kill_routes.rb +26 -0
  96. data/examples/mongrel_test_suite/lib/gen.rb +24 -0
  97. data/examples/mongrel_test_suite/test/camping/static_files.rb +9 -0
  98. data/examples/mongrel_test_suite/test/camping/upload_file.rb +9 -0
  99. data/examples/mongrel_test_suite/test/camping/upload_progress.rb +9 -0
  100. data/examples/mongrel_test_suite/test/http/base_protocol.rb +23 -0
  101. data/examples/mongrel_test_suite/test/nitro/upload_file.rb +9 -0
  102. data/examples/mongrel_test_suite/test/nitro/upload_progress.rb +9 -0
  103. data/examples/mongrel_test_suite/test/rails/static_files.rb +9 -0
  104. data/examples/mongrel_test_suite/test/rails/upload_file.rb +9 -0
  105. data/examples/mongrel_test_suite/test/rails/upload_progress.rb +9 -0
  106. data/examples/perftest.rb +30 -0
  107. data/ext/fuzzrnd/ext_help.h +14 -0
  108. data/ext/fuzzrnd/extconf.rb +6 -0
  109. data/ext/fuzzrnd/fuzzrnd.c +149 -0
  110. data/ext/http11_client/ext_help.h +14 -0
  111. data/ext/http11_client/extconf.rb +6 -0
  112. data/ext/http11_client/http11_client.c +288 -0
  113. data/ext/http11_client/http11_parser.c +629 -0
  114. data/ext/http11_client/http11_parser.h +46 -0
  115. data/ext/http11_client/http11_parser.rl +169 -0
  116. data/lib/rfuzz/client.rb +498 -0
  117. data/lib/rfuzz/random.rb +110 -0
  118. data/lib/rfuzz/rfuzz.rb +12 -0
  119. data/lib/rfuzz/session.rb +154 -0
  120. data/lib/rfuzz/stats.rb +159 -0
  121. data/resources/defaults.yaml +2 -0
  122. data/resources/words.txt +3310 -0
  123. data/test/coverage/index.html +388 -0
  124. data/test/coverage/lib-rfuzz-client_rb.html +1127 -0
  125. data/test/coverage/lib-rfuzz-random_rb.html +739 -0
  126. data/test/coverage/lib-rfuzz-session_rb.html +783 -0
  127. data/test/coverage/lib-rfuzz-stats_rb.html +788 -0
  128. data/test/server.rb +101 -0
  129. data/test/test_client.rb +164 -0
  130. data/test/test_fuzzrnd.rb +31 -0
  131. data/test/test_httpparser.rb +48 -0
  132. data/test/test_random.rb +75 -0
  133. data/test/test_session.rb +33 -0
  134. data/test/test_stats.rb +45 -0
  135. data/tools/rakehelp.rb +119 -0
  136. metadata +201 -0
@@ -0,0 +1,388 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <title>C0 code coverage information</title>
5
+ <style type='text/css'>body { background-color: rgb(240, 240, 245); }</style>
6
+ <style type='text/css'>span.cross-ref-title {
7
+ font-size: 140%;
8
+ }
9
+ span.cross-ref a {
10
+ text-decoration: none;
11
+ }
12
+ span.cross-ref {
13
+ background-color:#f3f7fa;
14
+ border: 1px dashed #333;
15
+ margin: 1em;
16
+ padding: 0.5em;
17
+ overflow: hidden;
18
+ }
19
+ a.crossref-toggle {
20
+ text-decoration: none;
21
+ }
22
+ span.marked0 {
23
+ background-color: rgb(185, 210, 200);
24
+ display: block;
25
+ }
26
+ span.marked1 {
27
+ background-color: rgb(190, 215, 205);
28
+ display: block;
29
+ }
30
+ span.inferred0 {
31
+ background-color: rgb(175, 200, 200);
32
+ display: block;
33
+ }
34
+ span.inferred1 {
35
+ background-color: rgb(180, 205, 205);
36
+ display: block;
37
+ }
38
+ span.uncovered0 {
39
+ background-color: rgb(225, 110, 110);
40
+ display: block;
41
+ }
42
+ span.uncovered1 {
43
+ background-color: rgb(235, 120, 120);
44
+ display: block;
45
+ }
46
+ span.overview {
47
+ border-bottom: 8px solid black;
48
+ }
49
+ div.overview {
50
+ border-bottom: 8px solid black;
51
+ }
52
+ body {
53
+ font-family: verdana, arial, helvetica;
54
+ }
55
+ div.footer {
56
+ font-size: 68%;
57
+ margin-top: 1.5em;
58
+ }
59
+ h1, h2, h3, h4, h5, h6 {
60
+ margin-bottom: 0.5em;
61
+ }
62
+ h5 {
63
+ margin-top: 0.5em;
64
+ }
65
+ .hidden {
66
+ display: none;
67
+ }
68
+ div.separator {
69
+ height: 10px;
70
+ }
71
+ /* Commented out for better readability, esp. on IE */
72
+ /*
73
+ table tr td, table tr th {
74
+ font-size: 68%;
75
+ }
76
+ td.value table tr td {
77
+ font-size: 11px;
78
+ }
79
+ */
80
+ table.percent_graph {
81
+ height: 12px;
82
+ border: #808080 1px solid;
83
+ empty-cells: show;
84
+ }
85
+ table.percent_graph td.covered {
86
+ height: 10px;
87
+ background: #00f000;
88
+ }
89
+ table.percent_graph td.uncovered {
90
+ height: 10px;
91
+ background: #e00000;
92
+ }
93
+ table.percent_graph td.NA {
94
+ height: 10px;
95
+ background: #eaeaea;
96
+ }
97
+ table.report {
98
+ border-collapse: collapse;
99
+ width: 100%;
100
+ }
101
+ table.report td.heading {
102
+ background: #dcecff;
103
+ border: #d0d0d0 1px solid;
104
+ font-weight: bold;
105
+ text-align: center;
106
+ }
107
+ table.report td.heading:hover {
108
+ background: #c0ffc0;
109
+ }
110
+ table.report td.text {
111
+ border: #d0d0d0 1px solid;
112
+ }
113
+ table.report td.value {
114
+ text-align: right;
115
+ border: #d0d0d0 1px solid;
116
+ }
117
+ table.report tr.light {
118
+ background-color: rgb(240, 240, 245);
119
+ }
120
+ table.report tr.dark {
121
+ background-color: rgb(230, 230, 235);
122
+ }
123
+ </style>
124
+ <script type='text/javascript'>
125
+ // <![CDATA[
126
+ function toggleCode( id ) {
127
+ if ( document.getElementById )
128
+ elem = document.getElementById( id );
129
+ else if ( document.all )
130
+ elem = eval( "document.all." + id );
131
+ else
132
+ return false;
133
+
134
+ elemStyle = elem.style;
135
+
136
+ if ( elemStyle.display != "block" ) {
137
+ elemStyle.display = "block"
138
+ } else {
139
+ elemStyle.display = "none"
140
+ }
141
+
142
+ return true;
143
+ }
144
+
145
+ // Make cross-references hidden by default
146
+ document.writeln( "<style type=\"text/css\">span.cross-ref { display: none }</style>" )
147
+ // ]]>
148
+ </script>
149
+ </head>
150
+ <body>
151
+ <h3>C0 code coverage information</h3>
152
+ <p>Generated on Wed Jul 19 17:39:34 EDT 2006 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.6.0</a>
153
+ </p>
154
+ <hr /> <table class='report'>
155
+ <thead>
156
+ <tr>
157
+ <td class='heading'>Name</td>
158
+ <td class='heading'>Total lines</td>
159
+ <td class='heading'>Lines of code</td>
160
+ <td class='heading'>Total coverage</td>
161
+ <td class='heading'>Code coverage</td>
162
+ </tr>
163
+ </thead>
164
+ <tbody>
165
+ <tr class='light'>
166
+ <td>TOTAL</td>
167
+ <td class='value'>
168
+ <tt>921</tt>
169
+ </td>
170
+ <td class='value'>
171
+ <tt>522</tt>
172
+ </td>
173
+ <td>
174
+ <table cellspacing='0' cellpadding='0' align='right'>
175
+ <tr>
176
+ <td>
177
+ <tt>93.1%</tt>&nbsp;</td>
178
+ <td>
179
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
180
+ <tr>
181
+ <td class='covered' width='93' />
182
+ <td class='uncovered' width='7' />
183
+ </tr>
184
+ </table>
185
+ </td>
186
+ </tr>
187
+ </table>
188
+ </td>
189
+ <td>
190
+ <table cellspacing='0' cellpadding='0' align='right'>
191
+ <tr>
192
+ <td>
193
+ <tt>89.1%</tt>&nbsp;</td>
194
+ <td>
195
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
196
+ <tr>
197
+ <td class='covered' width='89' />
198
+ <td class='uncovered' width='11' />
199
+ </tr>
200
+ </table>
201
+ </td>
202
+ </tr>
203
+ </table>
204
+ </td>
205
+ </tr>
206
+ <tr class='dark'>
207
+ <td>
208
+ <a href='lib-rfuzz-client_rb.html'>lib/rfuzz/client.rb</a>
209
+ </td>
210
+ <td class='value'>
211
+ <tt>498</tt>
212
+ </td>
213
+ <td class='value'>
214
+ <tt>275</tt>
215
+ </td>
216
+ <td>
217
+ <table cellspacing='0' cellpadding='0' align='right'>
218
+ <tr>
219
+ <td>
220
+ <tt>91.0%</tt>&nbsp;</td>
221
+ <td>
222
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
223
+ <tr>
224
+ <td class='covered' width='91' />
225
+ <td class='uncovered' width='9' />
226
+ </tr>
227
+ </table>
228
+ </td>
229
+ </tr>
230
+ </table>
231
+ </td>
232
+ <td>
233
+ <table cellspacing='0' cellpadding='0' align='right'>
234
+ <tr>
235
+ <td>
236
+ <tt>86.2%</tt>&nbsp;</td>
237
+ <td>
238
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
239
+ <tr>
240
+ <td class='covered' width='86' />
241
+ <td class='uncovered' width='14' />
242
+ </tr>
243
+ </table>
244
+ </td>
245
+ </tr>
246
+ </table>
247
+ </td>
248
+ </tr>
249
+ <tr class='light'>
250
+ <td>
251
+ <a href='lib-rfuzz-random_rb.html'>lib/rfuzz/random.rb</a>
252
+ </td>
253
+ <td class='value'>
254
+ <tt>110</tt>
255
+ </td>
256
+ <td class='value'>
257
+ <tt>60</tt>
258
+ </td>
259
+ <td>
260
+ <table cellspacing='0' cellpadding='0' align='right'>
261
+ <tr>
262
+ <td>
263
+ <tt>100.0%</tt>&nbsp;</td>
264
+ <td>
265
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
266
+ <tr>
267
+ <td class='covered' width='100' />
268
+ <td class='uncovered' width='0' />
269
+ </tr>
270
+ </table>
271
+ </td>
272
+ </tr>
273
+ </table>
274
+ </td>
275
+ <td>
276
+ <table cellspacing='0' cellpadding='0' align='right'>
277
+ <tr>
278
+ <td>
279
+ <tt>100.0%</tt>&nbsp;</td>
280
+ <td>
281
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
282
+ <tr>
283
+ <td class='covered' width='100' />
284
+ <td class='uncovered' width='0' />
285
+ </tr>
286
+ </table>
287
+ </td>
288
+ </tr>
289
+ </table>
290
+ </td>
291
+ </tr>
292
+ <tr class='dark'>
293
+ <td>
294
+ <a href='lib-rfuzz-session_rb.html'>lib/rfuzz/session.rb</a>
295
+ </td>
296
+ <td class='value'>
297
+ <tt>154</tt>
298
+ </td>
299
+ <td class='value'>
300
+ <tt>92</tt>
301
+ </td>
302
+ <td>
303
+ <table cellspacing='0' cellpadding='0' align='right'>
304
+ <tr>
305
+ <td>
306
+ <tt>95.5%</tt>&nbsp;</td>
307
+ <td>
308
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
309
+ <tr>
310
+ <td class='covered' width='95' />
311
+ <td class='uncovered' width='5' />
312
+ </tr>
313
+ </table>
314
+ </td>
315
+ </tr>
316
+ </table>
317
+ </td>
318
+ <td>
319
+ <table cellspacing='0' cellpadding='0' align='right'>
320
+ <tr>
321
+ <td>
322
+ <tt>92.4%</tt>&nbsp;</td>
323
+ <td>
324
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
325
+ <tr>
326
+ <td class='covered' width='92' />
327
+ <td class='uncovered' width='8' />
328
+ </tr>
329
+ </table>
330
+ </td>
331
+ </tr>
332
+ </table>
333
+ </td>
334
+ </tr>
335
+ <tr class='light'>
336
+ <td>
337
+ <a href='lib-rfuzz-stats_rb.html'>lib/rfuzz/stats.rb</a>
338
+ </td>
339
+ <td class='value'>
340
+ <tt>159</tt>
341
+ </td>
342
+ <td class='value'>
343
+ <tt>95</tt>
344
+ </td>
345
+ <td>
346
+ <table cellspacing='0' cellpadding='0' align='right'>
347
+ <tr>
348
+ <td>
349
+ <tt>92.5%</tt>&nbsp;</td>
350
+ <td>
351
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
352
+ <tr>
353
+ <td class='covered' width='92' />
354
+ <td class='uncovered' width='8' />
355
+ </tr>
356
+ </table>
357
+ </td>
358
+ </tr>
359
+ </table>
360
+ </td>
361
+ <td>
362
+ <table cellspacing='0' cellpadding='0' align='right'>
363
+ <tr>
364
+ <td>
365
+ <tt>87.4%</tt>&nbsp;</td>
366
+ <td>
367
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
368
+ <tr>
369
+ <td class='covered' width='87' />
370
+ <td class='uncovered' width='13' />
371
+ </tr>
372
+ </table>
373
+ </td>
374
+ </tr>
375
+ </table>
376
+ </td>
377
+ </tr>
378
+ </tbody>
379
+ </table><hr /> <p>Generated using the <a href='http://eigenclass.org/hiki.rb?rcov'>rcov code coverage analysis tool for Ruby</a> version 0.6.0.</p><p>
380
+ <a href='http://validator.w3.org/check/referer'>
381
+ <img src='http://www.w3.org/Icons/valid-xhtml11' height='31' alt='Valid XHTML 1.1!' width='88' />
382
+ </a>
383
+ <a href='http://jigsaw.w3.org/css-validator/check/referer'>
384
+ <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Valid CSS!' style='border:0;width:88px;height:31px' />
385
+ </a>
386
+ </p>
387
+ </body>
388
+ </html>
@@ -0,0 +1,1127 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <title>lib/rfuzz/client.rb - C0 code coverage information</title>
5
+ <style type='text/css'>body { background-color: rgb(240, 240, 245); }</style>
6
+ <style type='text/css'>span.cross-ref-title {
7
+ font-size: 140%;
8
+ }
9
+ span.cross-ref a {
10
+ text-decoration: none;
11
+ }
12
+ span.cross-ref {
13
+ background-color:#f3f7fa;
14
+ border: 1px dashed #333;
15
+ margin: 1em;
16
+ padding: 0.5em;
17
+ overflow: hidden;
18
+ }
19
+ a.crossref-toggle {
20
+ text-decoration: none;
21
+ }
22
+ span.marked0 {
23
+ background-color: rgb(185, 210, 200);
24
+ display: block;
25
+ }
26
+ span.marked1 {
27
+ background-color: rgb(190, 215, 205);
28
+ display: block;
29
+ }
30
+ span.inferred0 {
31
+ background-color: rgb(175, 200, 200);
32
+ display: block;
33
+ }
34
+ span.inferred1 {
35
+ background-color: rgb(180, 205, 205);
36
+ display: block;
37
+ }
38
+ span.uncovered0 {
39
+ background-color: rgb(225, 110, 110);
40
+ display: block;
41
+ }
42
+ span.uncovered1 {
43
+ background-color: rgb(235, 120, 120);
44
+ display: block;
45
+ }
46
+ span.overview {
47
+ border-bottom: 8px solid black;
48
+ }
49
+ div.overview {
50
+ border-bottom: 8px solid black;
51
+ }
52
+ body {
53
+ font-family: verdana, arial, helvetica;
54
+ }
55
+ div.footer {
56
+ font-size: 68%;
57
+ margin-top: 1.5em;
58
+ }
59
+ h1, h2, h3, h4, h5, h6 {
60
+ margin-bottom: 0.5em;
61
+ }
62
+ h5 {
63
+ margin-top: 0.5em;
64
+ }
65
+ .hidden {
66
+ display: none;
67
+ }
68
+ div.separator {
69
+ height: 10px;
70
+ }
71
+ /* Commented out for better readability, esp. on IE */
72
+ /*
73
+ table tr td, table tr th {
74
+ font-size: 68%;
75
+ }
76
+ td.value table tr td {
77
+ font-size: 11px;
78
+ }
79
+ */
80
+ table.percent_graph {
81
+ height: 12px;
82
+ border: #808080 1px solid;
83
+ empty-cells: show;
84
+ }
85
+ table.percent_graph td.covered {
86
+ height: 10px;
87
+ background: #00f000;
88
+ }
89
+ table.percent_graph td.uncovered {
90
+ height: 10px;
91
+ background: #e00000;
92
+ }
93
+ table.percent_graph td.NA {
94
+ height: 10px;
95
+ background: #eaeaea;
96
+ }
97
+ table.report {
98
+ border-collapse: collapse;
99
+ width: 100%;
100
+ }
101
+ table.report td.heading {
102
+ background: #dcecff;
103
+ border: #d0d0d0 1px solid;
104
+ font-weight: bold;
105
+ text-align: center;
106
+ }
107
+ table.report td.heading:hover {
108
+ background: #c0ffc0;
109
+ }
110
+ table.report td.text {
111
+ border: #d0d0d0 1px solid;
112
+ }
113
+ table.report td.value {
114
+ text-align: right;
115
+ border: #d0d0d0 1px solid;
116
+ }
117
+ table.report tr.light {
118
+ background-color: rgb(240, 240, 245);
119
+ }
120
+ table.report tr.dark {
121
+ background-color: rgb(230, 230, 235);
122
+ }
123
+ </style>
124
+ <script type='text/javascript'>
125
+ // <![CDATA[
126
+ function toggleCode( id ) {
127
+ if ( document.getElementById )
128
+ elem = document.getElementById( id );
129
+ else if ( document.all )
130
+ elem = eval( "document.all." + id );
131
+ else
132
+ return false;
133
+
134
+ elemStyle = elem.style;
135
+
136
+ if ( elemStyle.display != "block" ) {
137
+ elemStyle.display = "block"
138
+ } else {
139
+ elemStyle.display = "none"
140
+ }
141
+
142
+ return true;
143
+ }
144
+
145
+ // Make cross-references hidden by default
146
+ document.writeln( "<style type=\"text/css\">span.cross-ref { display: none }</style>" )
147
+ // ]]>
148
+ </script>
149
+ <style type='text/css'>span.run0 {
150
+ background-color: rgb(178, 204, 255);
151
+ display: block;
152
+ }
153
+ span.run1 {
154
+ background-color: rgb(178, 206, 255);
155
+ display: block;
156
+ }
157
+ span.run2 {
158
+ background-color: rgb(178, 209, 255);
159
+ display: block;
160
+ }
161
+ span.run3 {
162
+ background-color: rgb(178, 211, 255);
163
+ display: block;
164
+ }
165
+ span.run4 {
166
+ background-color: rgb(178, 214, 255);
167
+ display: block;
168
+ }
169
+ span.run5 {
170
+ background-color: rgb(178, 218, 255);
171
+ display: block;
172
+ }
173
+ span.run6 {
174
+ background-color: rgb(178, 220, 255);
175
+ display: block;
176
+ }
177
+ span.run7 {
178
+ background-color: rgb(178, 223, 255);
179
+ display: block;
180
+ }
181
+ span.run8 {
182
+ background-color: rgb(178, 225, 255);
183
+ display: block;
184
+ }
185
+ span.run9 {
186
+ background-color: rgb(178, 228, 255);
187
+ display: block;
188
+ }
189
+ span.run10 {
190
+ background-color: rgb(178, 232, 255);
191
+ display: block;
192
+ }
193
+ span.run11 {
194
+ background-color: rgb(178, 234, 255);
195
+ display: block;
196
+ }
197
+ span.run12 {
198
+ background-color: rgb(178, 237, 255);
199
+ display: block;
200
+ }
201
+ span.run13 {
202
+ background-color: rgb(178, 239, 255);
203
+ display: block;
204
+ }
205
+ span.run14 {
206
+ background-color: rgb(178, 242, 255);
207
+ display: block;
208
+ }
209
+ span.run15 {
210
+ background-color: rgb(178, 246, 255);
211
+ display: block;
212
+ }
213
+ span.run16 {
214
+ background-color: rgb(178, 248, 255);
215
+ display: block;
216
+ }
217
+ span.run17 {
218
+ background-color: rgb(178, 251, 255);
219
+ display: block;
220
+ }
221
+ span.run18 {
222
+ background-color: rgb(178, 253, 255);
223
+ display: block;
224
+ }
225
+ span.run19 {
226
+ background-color: rgb(178, 255, 253);
227
+ display: block;
228
+ }
229
+ span.run20 {
230
+ background-color: rgb(178, 255, 249);
231
+ display: block;
232
+ }
233
+ span.run21 {
234
+ background-color: rgb(178, 255, 247);
235
+ display: block;
236
+ }
237
+ span.run22 {
238
+ background-color: rgb(178, 255, 244);
239
+ display: block;
240
+ }
241
+ span.run23 {
242
+ background-color: rgb(178, 255, 242);
243
+ display: block;
244
+ }
245
+ span.run24 {
246
+ background-color: rgb(178, 255, 239);
247
+ display: block;
248
+ }
249
+ span.run25 {
250
+ background-color: rgb(178, 255, 235);
251
+ display: block;
252
+ }
253
+ span.run26 {
254
+ background-color: rgb(178, 255, 233);
255
+ display: block;
256
+ }
257
+ span.run27 {
258
+ background-color: rgb(178, 255, 230);
259
+ display: block;
260
+ }
261
+ span.run28 {
262
+ background-color: rgb(178, 255, 228);
263
+ display: block;
264
+ }
265
+ span.run29 {
266
+ background-color: rgb(178, 255, 225);
267
+ display: block;
268
+ }
269
+ span.run30 {
270
+ background-color: rgb(178, 255, 221);
271
+ display: block;
272
+ }
273
+ span.run31 {
274
+ background-color: rgb(178, 255, 219);
275
+ display: block;
276
+ }
277
+ span.run32 {
278
+ background-color: rgb(178, 255, 216);
279
+ display: block;
280
+ }
281
+ span.run33 {
282
+ background-color: rgb(178, 255, 214);
283
+ display: block;
284
+ }
285
+ span.run34 {
286
+ background-color: rgb(178, 255, 211);
287
+ display: block;
288
+ }
289
+ span.run35 {
290
+ background-color: rgb(178, 255, 207);
291
+ display: block;
292
+ }
293
+ span.run36 {
294
+ background-color: rgb(178, 255, 205);
295
+ display: block;
296
+ }
297
+ span.run37 {
298
+ background-color: rgb(178, 255, 202);
299
+ display: block;
300
+ }
301
+ span.run38 {
302
+ background-color: rgb(178, 255, 200);
303
+ display: block;
304
+ }
305
+ span.run39 {
306
+ background-color: rgb(178, 255, 197);
307
+ display: block;
308
+ }
309
+ span.run40 {
310
+ background-color: rgb(178, 255, 193);
311
+ display: block;
312
+ }
313
+ span.run41 {
314
+ background-color: rgb(178, 255, 191);
315
+ display: block;
316
+ }
317
+ span.run42 {
318
+ background-color: rgb(178, 255, 188);
319
+ display: block;
320
+ }
321
+ span.run43 {
322
+ background-color: rgb(178, 255, 186);
323
+ display: block;
324
+ }
325
+ span.run44 {
326
+ background-color: rgb(178, 255, 183);
327
+ display: block;
328
+ }
329
+ span.run45 {
330
+ background-color: rgb(178, 255, 179);
331
+ display: block;
332
+ }
333
+ span.run46 {
334
+ background-color: rgb(179, 255, 178);
335
+ display: block;
336
+ }
337
+ span.run47 {
338
+ background-color: rgb(182, 255, 178);
339
+ display: block;
340
+ }
341
+ span.run48 {
342
+ background-color: rgb(184, 255, 178);
343
+ display: block;
344
+ }
345
+ span.run49 {
346
+ background-color: rgb(187, 255, 178);
347
+ display: block;
348
+ }
349
+ span.run50 {
350
+ background-color: rgb(191, 255, 178);
351
+ display: block;
352
+ }
353
+ span.run51 {
354
+ background-color: rgb(193, 255, 178);
355
+ display: block;
356
+ }
357
+ span.run52 {
358
+ background-color: rgb(196, 255, 178);
359
+ display: block;
360
+ }
361
+ span.run53 {
362
+ background-color: rgb(198, 255, 178);
363
+ display: block;
364
+ }
365
+ span.run54 {
366
+ background-color: rgb(201, 255, 178);
367
+ display: block;
368
+ }
369
+ span.run55 {
370
+ background-color: rgb(205, 255, 178);
371
+ display: block;
372
+ }
373
+ span.run56 {
374
+ background-color: rgb(207, 255, 178);
375
+ display: block;
376
+ }
377
+ span.run57 {
378
+ background-color: rgb(210, 255, 178);
379
+ display: block;
380
+ }
381
+ span.run58 {
382
+ background-color: rgb(212, 255, 178);
383
+ display: block;
384
+ }
385
+ span.run59 {
386
+ background-color: rgb(215, 255, 178);
387
+ display: block;
388
+ }
389
+ span.run60 {
390
+ background-color: rgb(219, 255, 178);
391
+ display: block;
392
+ }
393
+ span.run61 {
394
+ background-color: rgb(221, 255, 178);
395
+ display: block;
396
+ }
397
+ span.run62 {
398
+ background-color: rgb(224, 255, 178);
399
+ display: block;
400
+ }
401
+ span.run63 {
402
+ background-color: rgb(226, 255, 178);
403
+ display: block;
404
+ }
405
+ span.run64 {
406
+ background-color: rgb(229, 255, 178);
407
+ display: block;
408
+ }
409
+ span.run65 {
410
+ background-color: rgb(233, 255, 178);
411
+ display: block;
412
+ }
413
+ span.run66 {
414
+ background-color: rgb(235, 255, 178);
415
+ display: block;
416
+ }
417
+ span.run67 {
418
+ background-color: rgb(238, 255, 178);
419
+ display: block;
420
+ }
421
+ span.run68 {
422
+ background-color: rgb(240, 255, 178);
423
+ display: block;
424
+ }
425
+ span.run69 {
426
+ background-color: rgb(243, 255, 178);
427
+ display: block;
428
+ }
429
+ span.run70 {
430
+ background-color: rgb(247, 255, 178);
431
+ display: block;
432
+ }
433
+ span.run71 {
434
+ background-color: rgb(249, 255, 178);
435
+ display: block;
436
+ }
437
+ span.run72 {
438
+ background-color: rgb(252, 255, 178);
439
+ display: block;
440
+ }
441
+ span.run73 {
442
+ background-color: rgb(255, 255, 178);
443
+ display: block;
444
+ }
445
+ span.run74 {
446
+ background-color: rgb(255, 252, 178);
447
+ display: block;
448
+ }
449
+ span.run75 {
450
+ background-color: rgb(255, 248, 178);
451
+ display: block;
452
+ }
453
+ span.run76 {
454
+ background-color: rgb(255, 246, 178);
455
+ display: block;
456
+ }
457
+ span.run77 {
458
+ background-color: rgb(255, 243, 178);
459
+ display: block;
460
+ }
461
+ span.run78 {
462
+ background-color: rgb(255, 240, 178);
463
+ display: block;
464
+ }
465
+ span.run79 {
466
+ background-color: rgb(255, 238, 178);
467
+ display: block;
468
+ }
469
+ span.run80 {
470
+ background-color: rgb(255, 234, 178);
471
+ display: block;
472
+ }
473
+ span.run81 {
474
+ background-color: rgb(255, 232, 178);
475
+ display: block;
476
+ }
477
+ span.run82 {
478
+ background-color: rgb(255, 229, 178);
479
+ display: block;
480
+ }
481
+ span.run83 {
482
+ background-color: rgb(255, 226, 178);
483
+ display: block;
484
+ }
485
+ span.run84 {
486
+ background-color: rgb(255, 224, 178);
487
+ display: block;
488
+ }
489
+ span.run85 {
490
+ background-color: rgb(255, 220, 178);
491
+ display: block;
492
+ }
493
+ span.run86 {
494
+ background-color: rgb(255, 218, 178);
495
+ display: block;
496
+ }
497
+ span.run87 {
498
+ background-color: rgb(255, 215, 178);
499
+ display: block;
500
+ }
501
+ span.run88 {
502
+ background-color: rgb(255, 212, 178);
503
+ display: block;
504
+ }
505
+ span.run89 {
506
+ background-color: rgb(255, 210, 178);
507
+ display: block;
508
+ }
509
+ span.run90 {
510
+ background-color: rgb(255, 206, 178);
511
+ display: block;
512
+ }
513
+ span.run91 {
514
+ background-color: rgb(255, 204, 178);
515
+ display: block;
516
+ }
517
+ span.run92 {
518
+ background-color: rgb(255, 201, 178);
519
+ display: block;
520
+ }
521
+ span.run93 {
522
+ background-color: rgb(255, 198, 178);
523
+ display: block;
524
+ }
525
+ span.run94 {
526
+ background-color: rgb(255, 196, 178);
527
+ display: block;
528
+ }
529
+ span.run95 {
530
+ background-color: rgb(255, 192, 178);
531
+ display: block;
532
+ }
533
+ span.run96 {
534
+ background-color: rgb(255, 189, 178);
535
+ display: block;
536
+ }
537
+ span.run97 {
538
+ background-color: rgb(255, 187, 178);
539
+ display: block;
540
+ }
541
+ span.run98 {
542
+ background-color: rgb(255, 184, 178);
543
+ display: block;
544
+ }
545
+ span.run99 {
546
+ background-color: rgb(255, 182, 178);
547
+ display: block;
548
+ }
549
+ span.run100 {
550
+ background-color: rgb(255, 178, 178);
551
+ display: block;
552
+ }
553
+ </style>
554
+ </head>
555
+ <body>
556
+ <h3>C0 code coverage information</h3>
557
+ <p>Generated on Wed Jul 19 17:39:34 EDT 2006 with <a href='http://eigenclass.org/hiki.rb?rcov'>rcov 0.6.0</a>
558
+ </p>
559
+ <hr /><pre><span class='marked0'>Code reported as executed by Ruby looks like this...
560
+ </span><span class='marked1'>and this: this line is also marked as covered.
561
+ </span><span class='inferred0'>Lines considered as run by rcov, but not reported by Ruby, look like this,
562
+ </span><span class='inferred1'>and this: these lines were inferred by rcov (using simple heuristics).
563
+ </span><span class='uncovered0'>Finally, here&apos;s a line marked as not executed.
564
+ </span></pre>
565
+ <table class='report'>
566
+ <thead>
567
+ <tr>
568
+ <td class='heading'>Name</td>
569
+ <td class='heading'>Total lines</td>
570
+ <td class='heading'>Lines of code</td>
571
+ <td class='heading'>Total coverage</td>
572
+ <td class='heading'>Code coverage</td>
573
+ </tr>
574
+ </thead>
575
+ <tbody>
576
+ <tr class='light'>
577
+ <td>
578
+ <a href='lib-rfuzz-client_rb.html'>lib/rfuzz/client.rb</a>
579
+ </td>
580
+ <td class='value'>
581
+ <tt>498</tt>
582
+ </td>
583
+ <td class='value'>
584
+ <tt>275</tt>
585
+ </td>
586
+ <td>
587
+ <table cellspacing='0' cellpadding='0' align='right'>
588
+ <tr>
589
+ <td>
590
+ <tt>91.0%</tt>&nbsp;</td>
591
+ <td>
592
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
593
+ <tr>
594
+ <td class='covered' width='91' />
595
+ <td class='uncovered' width='9' />
596
+ </tr>
597
+ </table>
598
+ </td>
599
+ </tr>
600
+ </table>
601
+ </td>
602
+ <td>
603
+ <table cellspacing='0' cellpadding='0' align='right'>
604
+ <tr>
605
+ <td>
606
+ <tt>86.2%</tt>&nbsp;</td>
607
+ <td>
608
+ <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
609
+ <tr>
610
+ <td class='covered' width='86' />
611
+ <td class='uncovered' width='14' />
612
+ </tr>
613
+ </table>
614
+ </td>
615
+ </tr>
616
+ </table>
617
+ </td>
618
+ </tr>
619
+ </tbody>
620
+ </table><pre><span class="marked1"><a name="line1" /> 1 require 'http11_client'
621
+ </span><span class="marked0"><a name="line2" /> 2 require 'socket'
622
+ </span><span class="marked1"><a name="line3" /> 3 require 'stringio'
623
+ </span><span class="marked0"><a name="line4" /> 4 require 'rfuzz/stats'
624
+ </span><span class="marked1"><a name="line5" /> 5
625
+ </span><span class="marked0"><a name="line6" /> 6 module RFuzz
626
+ </span><span class="inferred1"><a name="line7" /> 7
627
+ </span><span class="inferred0"><a name="line8" /> 8
628
+ </span><span class="inferred1"><a name="line9" /> 9 # A simple hash is returned for each request made by HttpClient with
629
+ </span><span class="inferred0"><a name="line10" /> 10 # the headers that were given by the server for that request. Attached
630
+ </span><span class="inferred1"><a name="line11" /> 11 # to this are four attributes you can play with:
631
+ </span><span class="inferred0"><a name="line12" /> 12 #
632
+ </span><span class="inferred1"><a name="line13" /> 13 # * http_reason
633
+ </span><span class="inferred0"><a name="line14" /> 14 # * http_version
634
+ </span><span class="inferred1"><a name="line15" /> 15 # * http_status
635
+ </span><span class="inferred0"><a name="line16" /> 16 # * http_body
636
+ </span><span class="inferred1"><a name="line17" /> 17 #
637
+ </span><span class="inferred0"><a name="line18" /> 18 # These are set internally by the Ragel/C parser so they're very fast
638
+ </span><span class="inferred1"><a name="line19" /> 19 # and pretty much C voodoo. You can modify them without fear once you get
639
+ </span><span class="inferred0"><a name="line20" /> 20 # the response.
640
+ </span><span class="marked1"><a name="line21" /> 21 class HttpResponse &lt; Hash
641
+ </span><span class="inferred0"><a name="line22" /> 22 # The reason returned in the http response (&quot;OK&quot;,&quot;File not found&quot;,etc.)
642
+ </span><span class="marked1"><a name="line23" /> 23 attr_accessor :http_reason
643
+ </span><span class="inferred0"><a name="line24" /> 24
644
+ </span><span class="inferred1"><a name="line25" /> 25 # The HTTP version returned.
645
+ </span><span class="marked0"><a name="line26" /> 26 attr_accessor :http_version
646
+ </span><span class="inferred1"><a name="line27" /> 27
647
+ </span><span class="inferred0"><a name="line28" /> 28 # The status code (as a string!)
648
+ </span><span class="marked1"><a name="line29" /> 29 attr_accessor :http_status
649
+ </span><span class="inferred0"><a name="line30" /> 30
650
+ </span><span class="inferred1"><a name="line31" /> 31 # The http body of the response, in the raw
651
+ </span><span class="marked0"><a name="line32" /> 32 attr_accessor :http_body
652
+ </span><span class="inferred1"><a name="line33" /> 33
653
+ </span><span class="inferred0"><a name="line34" /> 34 # When parsing chunked encodings this is set
654
+ </span><span class="marked1"><a name="line35" /> 35 attr_accessor :http_chunk_size
655
+ </span><span class="inferred0"><a name="line36" /> 36 end
656
+ </span><span class="inferred1"><a name="line37" /> 37
657
+ </span><span class="inferred0"><a name="line38" /> 38 # A mixin that has most of the HTTP encoding methods you need to work
658
+ </span><span class="inferred1"><a name="line39" /> 39 # with the protocol. It's used by HttpClient, but you can use it
659
+ </span><span class="inferred0"><a name="line40" /> 40 # as well.
660
+ </span><span class="marked1"><a name="line41" /> 41 module HttpEncoding
661
+ </span><span class="inferred0"><a name="line42" /> 42
662
+ </span><span class="inferred1"><a name="line43" /> 43 # Converts a Hash of cookies to the appropriate simple cookie
663
+ </span><span class="inferred0"><a name="line44" /> 44 # headers.
664
+ </span><span class="marked1"><a name="line45" /> 45 def encode_cookies(cookies)
665
+ </span><span class="marked0"><a name="line46" /> 46 result = &quot;&quot;
666
+ </span><span class="marked1"><a name="line47" /> 47 cookies.each do |k,v|
667
+ </span><span class="marked0"><a name="line48" /> 48 if v.kind_of? Array
668
+ </span><span class="uncovered1"><a name="line49" /> 49 v.each {|x| result += encode_field(&quot;Cookie&quot;, encode_param(k,x)) }
669
+ </span><span class="inferred0"><a name="line50" /> 50 else
670
+ </span><span class="marked1"><a name="line51" /> 51 result += encode_field(&quot;Cookie&quot;, encode_param(k,v))
671
+ </span><span class="marked0"><a name="line52" /> 52 end
672
+ </span><span class="inferred1"><a name="line53" /> 53 end
673
+ </span><span class="marked0"><a name="line54" /> 54 return result
674
+ </span><span class="inferred1"><a name="line55" /> 55 end
675
+ </span><span class="inferred0"><a name="line56" /> 56
676
+ </span><span class="inferred1"><a name="line57" /> 57 # Encode HTTP header fields of &quot;k: v\r\n&quot;
677
+ </span><span class="marked0"><a name="line58" /> 58 def encode_field(k,v)
678
+ </span><span class="marked1"><a name="line59" /> 59 &quot;#{k}: #{v}\r\n&quot;
679
+ </span><span class="marked0"><a name="line60" /> 60 end
680
+ </span><span class="inferred1"><a name="line61" /> 61
681
+ </span><span class="inferred0"><a name="line62" /> 62 # Encodes the headers given in the hash returning a string
682
+ </span><span class="inferred1"><a name="line63" /> 63 # you can use.
683
+ </span><span class="marked0"><a name="line64" /> 64 def encode_headers(head)
684
+ </span><span class="marked1"><a name="line65" /> 65 result = &quot;&quot;
685
+ </span><span class="marked0"><a name="line66" /> 66 head.each do |k,v|
686
+ </span><span class="marked1"><a name="line67" /> 67 if v.kind_of? Array
687
+ </span><span class="marked0"><a name="line68" /> 68 v.each {|x| result += encode_field(k,x) }
688
+ </span><span class="marked1"><a name="line69" /> 69 else
689
+ </span><span class="marked0"><a name="line70" /> 70 result += encode_field(k,v)
690
+ </span><span class="marked1"><a name="line71" /> 71 end
691
+ </span><span class="inferred0"><a name="line72" /> 72 end
692
+ </span><span class="marked1"><a name="line73" /> 73 return result
693
+ </span><span class="inferred0"><a name="line74" /> 74 end
694
+ </span><span class="inferred1"><a name="line75" /> 75
695
+ </span><span class="inferred0"><a name="line76" /> 76 # URL encodes a single k=v parameter.
696
+ </span><span class="marked1"><a name="line77" /> 77 def encode_param(k,v)
697
+ </span><span class="marked0"><a name="line78" /> 78 escape(k) + &quot;=&quot; + escape(v)
698
+ </span><span class="marked1"><a name="line79" /> 79 end
699
+ </span><span class="inferred0"><a name="line80" /> 80
700
+ </span><span class="inferred1"><a name="line81" /> 81 # Takes a query string and encodes it as a URL encoded
701
+ </span><span class="inferred0"><a name="line82" /> 82 # set of key=value pairs with &amp; separating them.
702
+ </span><span class="marked1"><a name="line83" /> 83 def encode_query(uri, query)
703
+ </span><span class="marked0"><a name="line84" /> 84 params = []
704
+ </span><span class="inferred1"><a name="line85" /> 85
705
+ </span><span class="marked0"><a name="line86" /> 86 if query
706
+ </span><span class="marked1"><a name="line87" /> 87 query.each do |k,v|
707
+ </span><span class="marked0"><a name="line88" /> 88 if v.kind_of? Array
708
+ </span><span class="marked1"><a name="line89" /> 89 v.each {|x| params &lt;&lt; encode_param(k,x) }
709
+ </span><span class="marked0"><a name="line90" /> 90 else
710
+ </span><span class="marked1"><a name="line91" /> 91 params &lt;&lt; encode_param(k,v)
711
+ </span><span class="marked0"><a name="line92" /> 92 end
712
+ </span><span class="inferred1"><a name="line93" /> 93 end
713
+ </span><span class="inferred0"><a name="line94" /> 94
714
+ </span><span class="marked1"><a name="line95" /> 95 uri += &quot;?&quot; + params.join('&amp;')
715
+ </span><span class="inferred0"><a name="line96" /> 96 end
716
+ </span><span class="inferred1"><a name="line97" /> 97
717
+ </span><span class="marked0"><a name="line98" /> 98 return uri
718
+ </span><span class="inferred1"><a name="line99" /> 99 end
719
+ </span><span class="inferred0"><a name="line100" />100
720
+ </span><span class="inferred1"><a name="line101" />101 # HTTP is kind of retarded that you have to specify
721
+ </span><span class="inferred0"><a name="line102" />102 # a Host header, but if you include port 80 then further
722
+ </span><span class="inferred1"><a name="line103" />103 # redirects will tack on the :80 which is annoying.
723
+ </span><span class="marked0"><a name="line104" />104 def encode_host(host, port)
724
+ </span><span class="marked1"><a name="line105" />105 &quot;#{host}&quot; + (port.to_i != 80 ? &quot;:#{port}&quot; : &quot;&quot;)
725
+ </span><span class="marked0"><a name="line106" />106 end
726
+ </span><span class="inferred1"><a name="line107" />107
727
+ </span><span class="inferred0"><a name="line108" />108 # Performs URI escaping so that you can construct proper
728
+ </span><span class="inferred1"><a name="line109" />109 # query strings faster. Use this rather than the cgi.rb
729
+ </span><span class="inferred0"><a name="line110" />110 # version since it's faster. (Stolen from Camping).
730
+ </span><span class="marked1"><a name="line111" />111 def escape(s)
731
+ </span><span class="marked0"><a name="line112" />112 s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
732
+ </span><span class="inferred1"><a name="line113" />113 '%'+$1.unpack('H2'*$1.size).join('%').upcase
733
+ </span><span class="inferred0"><a name="line114" />114 }.tr(' ', '+')
734
+ </span><span class="marked1"><a name="line115" />115 end
735
+ </span><span class="inferred0"><a name="line116" />116
736
+ </span><span class="inferred1"><a name="line117" />117
737
+ </span><span class="inferred0"><a name="line118" />118 # Unescapes a URI escaped string. (Stolen from Camping).
738
+ </span><span class="marked1"><a name="line119" />119 def unescape(s)
739
+ </span><span class="marked0"><a name="line120" />120 s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
740
+ </span><span class="inferred1"><a name="line121" />121 [$1.delete('%')].pack('H*')
741
+ </span><span class="inferred0"><a name="line122" />122 }
742
+ </span><span class="marked1"><a name="line123" />123 end
743
+ </span><span class="inferred0"><a name="line124" />124
744
+ </span><span class="inferred1"><a name="line125" />125 # Parses a query string by breaking it up at the '&amp;'
745
+ </span><span class="inferred0"><a name="line126" />126 # and ';' characters. You can also use this to parse
746
+ </span><span class="inferred1"><a name="line127" />127 # cookies by changing the characters used in the second
747
+ </span><span class="inferred0"><a name="line128" />128 # parameter (which defaults to '&amp;;'.
748
+ </span><span class="marked1"><a name="line129" />129 def query_parse(qs, d = '&amp;;')
749
+ </span><span class="marked0"><a name="line130" />130 params = {}
750
+ </span><span class="marked1"><a name="line131" />131 (qs||'').split(/[#{d}] */n).inject(params) { |h,p|
751
+ </span><span class="marked0"><a name="line132" />132 k, v=unescape(p).split('=',2)
752
+ </span><span class="marked1"><a name="line133" />133 if cur = params[k]
753
+ </span><span class="uncovered0"><a name="line134" />134 if cur.class == Array
754
+ </span><span class="uncovered1"><a name="line135" />135 params[k] &lt;&lt; v
755
+ </span><span class="uncovered0"><a name="line136" />136 else
756
+ </span><span class="uncovered1"><a name="line137" />137 params[k] = [cur, v]
757
+ </span><span class="uncovered0"><a name="line138" />138 end
758
+ </span><span class="inferred1"><a name="line139" />139 else
759
+ </span><span class="marked0"><a name="line140" />140 params[k] = v
760
+ </span><span class="inferred1"><a name="line141" />141 end
761
+ </span><span class="inferred0"><a name="line142" />142 }
762
+ </span><span class="inferred1"><a name="line143" />143
763
+ </span><span class="marked0"><a name="line144" />144 return params
764
+ </span><span class="inferred1"><a name="line145" />145 end
765
+ </span><span class="inferred0"><a name="line146" />146 end
766
+ </span><span class="inferred1"><a name="line147" />147
767
+ </span><span class="inferred0"><a name="line148" />148
768
+ </span><span class="inferred1"><a name="line149" />149 # The actual HttpClient that does the work with the thinnest
769
+ </span><span class="inferred0"><a name="line150" />150 # layer between you and the protocol. All exceptions and leaks
770
+ </span><span class="inferred1"><a name="line151" />151 # are allowed to pass through since those are important when
771
+ </span><span class="inferred0"><a name="line152" />152 # testing. It doesn't pretend to be a full client, but instead
772
+ </span><span class="inferred1"><a name="line153" />153 # is just enough client to track cookies, form proper HTTP requests,
773
+ </span><span class="inferred0"><a name="line154" />154 # and return HttpResponse hashes with the results.
774
+ </span><span class="inferred1"><a name="line155" />155 #
775
+ </span><span class="inferred0"><a name="line156" />156 # It's designed so that you create one client, and then you work it
776
+ </span><span class="inferred1"><a name="line157" />157 # with a minimum of parameters as you need. The initialize method
777
+ </span><span class="inferred0"><a name="line158" />158 # lets you pass in defaults for most of the parameters you'll need,
778
+ </span><span class="inferred1"><a name="line159" />159 # and you can simple call the method you want and it'll be translated
779
+ </span><span class="inferred0"><a name="line160" />160 # to an HTTP method (client.get =&gt; GET, client.foobar = FOOBAR).
780
+ </span><span class="inferred1"><a name="line161" />161 #
781
+ </span><span class="inferred0"><a name="line162" />162 # Here's a few examples:
782
+ </span><span class="inferred1"><a name="line163" />163 #
783
+ </span><span class="inferred0"><a name="line164" />164 # client = HttpClient.new(:head =&gt; {&quot;X-DefaultHeader&quot; =&gt; &quot;ONE&quot;})
784
+ </span><span class="inferred1"><a name="line165" />165 # resp = client.post(&quot;/test&quot;)
785
+ </span><span class="inferred0"><a name="line166" />166 # resp = client.post(&quot;/test&quot;, :head =&gt; {&quot;X-TestSend&quot; =&gt; &quot;Status&quot;}, :body =&gt; &quot;TEST BODY&quot;)
786
+ </span><span class="inferred1"><a name="line167" />167 # resp = client.put(&quot;/testput&quot;, :query =&gt; {&quot;q&quot; =&gt; &quot;test&quot;}, :body =&gt; &quot;SOME JUNK&quot;)
787
+ </span><span class="inferred0"><a name="line168" />168 # client.reset
788
+ </span><span class="inferred1"><a name="line169" />169 #
789
+ </span><span class="inferred0"><a name="line170" />170 # The HttpClient.reset call clears cookies that are maintained.
790
+ </span><span class="inferred1"><a name="line171" />171 #
791
+ </span><span class="inferred0"><a name="line172" />172 # It uses method_missing to do the translation of .put to &quot;PUT /testput HTTP/1.1&quot;
792
+ </span><span class="inferred1"><a name="line173" />173 # so you can get into trouble if you're calling unknown methods on it. By
793
+ </span><span class="inferred0"><a name="line174" />174 # default the methods are PUT, GET, POST, DELETE, HEAD. You can change
794
+ </span><span class="inferred1"><a name="line175" />175 # the allowed methods by passing :allowed_methods =&gt; [:put, :get, ..] to
795
+ </span><span class="inferred0"><a name="line176" />176 # the initialize for the object.
796
+ </span><span class="inferred1"><a name="line177" />177 #
797
+ </span><span class="inferred0"><a name="line178" />178 # == Notifications
798
+ </span><span class="inferred1"><a name="line179" />179 #
799
+ </span><span class="inferred0"><a name="line180" />180 # You can register a &quot;notifier&quot; with the client that will get called when
800
+ </span><span class="inferred1"><a name="line181" />181 # different events happen. Right now the Notifier class just has a few
801
+ </span><span class="inferred0"><a name="line182" />182 # functions for the common parts of an HTTP request that each take a
802
+ </span><span class="inferred1"><a name="line183" />183 # symbol and some extra parameters. See RFuzz::Notifier for more
803
+ </span><span class="inferred0"><a name="line184" />184 # information.
804
+ </span><span class="inferred1"><a name="line185" />185 #
805
+ </span><span class="inferred0"><a name="line186" />186 # == Parameters
806
+ </span><span class="inferred1"><a name="line187" />187 #
807
+ </span><span class="inferred0"><a name="line188" />188 # :head =&gt; {K =&gt; V} or {K =&gt; [V1,V2]}
808
+ </span><span class="inferred1"><a name="line189" />189 # :query =&gt; {K =&gt; V} or {K =&gt; [V1,V2]}
809
+ </span><span class="inferred0"><a name="line190" />190 # :body =&gt; &quot;some body&quot; (you must encode for now)
810
+ </span><span class="inferred1"><a name="line191" />191 # :cookies =&gt; {K =&gt; V} or {K =&gt; [V1, V2]}
811
+ </span><span class="inferred0"><a name="line192" />192 # :allowed_methods =&gt; [:put, :get, :post, :delete, :head]
812
+ </span><span class="inferred1"><a name="line193" />193 # :notifier =&gt; Notifier.new
813
+ </span><span class="inferred0"><a name="line194" />194 # :redirect =&gt; false (give it a number and it'll follow redirects for that count)
814
+ </span><span class="inferred1"><a name="line195" />195 #
815
+ </span><span class="marked0"><a name="line196" />196 class HttpClient
816
+ </span><span class="marked1"><a name="line197" />197 include HttpEncoding
817
+ </span><span class="inferred0"><a name="line198" />198
818
+ </span><span class="marked1"><a name="line199" />199 TRANSFER_ENCODING=&quot;TRANSFER_ENCODING&quot;
819
+ </span><span class="marked0"><a name="line200" />200 CONTENT_LENGTH=&quot;CONTENT_LENGTH&quot;
820
+ </span><span class="marked1"><a name="line201" />201 SET_COOKIE=&quot;SET_COOKIE&quot;
821
+ </span><span class="marked0"><a name="line202" />202 LOCATION=&quot;LOCATION&quot;
822
+ </span><span class="marked1"><a name="line203" />203 HOST=&quot;HOST&quot;
823
+ </span><span class="marked0"><a name="line204" />204 HTTP_REQUEST_HEADER=&quot;%s %s HTTP/1.1\r\n&quot;
824
+ </span><span class="inferred1"><a name="line205" />205
825
+ </span><span class="inferred0"><a name="line206" />206 # Access to the host, port, default options, and cookies currently in play
826
+ </span><span class="marked1"><a name="line207" />207 attr_accessor :host, :port, :options, :cookies, :allowed_methods, :notifier
827
+ </span><span class="inferred0"><a name="line208" />208
828
+ </span><span class="inferred1"><a name="line209" />209 # Doesn't make the connect until you actually call a .put,.get, etc.
829
+ </span><span class="marked0"><a name="line210" />210 def initialize(host, port, options = {})
830
+ </span><span class="marked1"><a name="line211" />211 @options = options
831
+ </span><span class="marked0"><a name="line212" />212 @host = host
832
+ </span><span class="marked1"><a name="line213" />213 @port = port
833
+ </span><span class="marked0"><a name="line214" />214 @cookies = options[:cookies] || {}
834
+ </span><span class="marked1"><a name="line215" />215 @allowed_methods = options[:allowed_methods] || [:put, :get, :post, :delete, :head]
835
+ </span><span class="marked0"><a name="line216" />216 @notifier = options[:notifier]
836
+ </span><span class="marked1"><a name="line217" />217 @redirect = options[:redirect] || false
837
+ </span><span class="inferred0"><a name="line218" />218 end
838
+ </span><span class="inferred1"><a name="line219" />219
839
+ </span><span class="inferred0"><a name="line220" />220
840
+ </span><span class="inferred1"><a name="line221" />221 # Builds a full request from the method, uri, req, and @cookies
841
+ </span><span class="inferred0"><a name="line222" />222 # using the default @options and writes it to out (should be an IO).
842
+ </span><span class="inferred1"><a name="line223" />223 #
843
+ </span><span class="inferred0"><a name="line224" />224 # It returns the body that the caller should use (based on defaults
844
+ </span><span class="inferred1"><a name="line225" />225 # resolution).
845
+ </span><span class="marked0"><a name="line226" />226 def build_request(out, method, uri, req)
846
+ </span><span class="marked1"><a name="line227" />227 ops = @options.merge(req)
847
+ </span><span class="marked0"><a name="line228" />228 query = ops[:query]
848
+ </span><span class="inferred1"><a name="line229" />229
849
+ </span><span class="inferred0"><a name="line230" />230 # merge head differently since that's typically what they mean
850
+ </span><span class="marked1"><a name="line231" />231 head = req[:head] || {}
851
+ </span><span class="marked0"><a name="line232" />232 head = ops[:head].merge(head) if ops[:head]
852
+ </span><span class="inferred1"><a name="line233" />233
853
+ </span><span class="inferred0"><a name="line234" />234 # setup basic headers we always need
854
+ </span><span class="marked1"><a name="line235" />235 head[HOST] = encode_host(@host,@port)
855
+ </span><span class="marked0"><a name="line236" />236 head[CONTENT_LENGTH] = ops[:body] ? ops[:body].length : 0
856
+ </span><span class="inferred1"><a name="line237" />237
857
+ </span><span class="inferred0"><a name="line238" />238 # blast it out
858
+ </span><span class="marked1"><a name="line239" />239 out.write(HTTP_REQUEST_HEADER % [method, encode_query(uri,query)])
859
+ </span><span class="marked0"><a name="line240" />240 out.write(encode_headers(head))
860
+ </span><span class="marked1"><a name="line241" />241 out.write(encode_cookies(@cookies.merge(req[:cookies] || {})))
861
+ </span><span class="marked0"><a name="line242" />242 out.write(&quot;\r\n&quot;)
862
+ </span><span class="marked1"><a name="line243" />243 ops[:body] || &quot;&quot;
863
+ </span><span class="inferred0"><a name="line244" />244 end
864
+ </span><span class="inferred1"><a name="line245" />245
865
+ </span><span class="marked0"><a name="line246" />246 def read_chunks(input, out, parser)
866
+ </span><span class="marked1"><a name="line247" />247 begin
867
+ </span><span class="marked0"><a name="line248" />248 until input.closed?
868
+ </span><span class="marked1"><a name="line249" />249 parser.reset
869
+ </span><span class="marked0"><a name="line250" />250 chunk = HttpResponse.new
870
+ </span><span class="marked1"><a name="line251" />251 line = input.readline(&quot;\r\n&quot;)
871
+ </span><span class="marked0"><a name="line252" />252 nread = parser.execute(chunk, line, 0)
872
+ </span><span class="inferred1"><a name="line253" />253
873
+ </span><span class="marked0"><a name="line254" />254 if !parser.finished?
874
+ </span><span class="uncovered1"><a name="line255" />255 # tried to read this header but couldn't
875
+ </span><span class="uncovered0"><a name="line256" />256 return :incomplete_header, line
876
+ </span><span class="uncovered1"><a name="line257" />257 end
877
+ </span><span class="inferred0"><a name="line258" />258
878
+ </span><span class="marked1"><a name="line259" />259 size = chunk.http_chunk_size ? chunk.http_chunk_size.to_i(base=16) : 0
879
+ </span><span class="inferred0"><a name="line260" />260
880
+ </span><span class="marked1"><a name="line261" />261 if size == 0
881
+ </span><span class="marked0"><a name="line262" />262 return :finished, nil
882
+ </span><span class="inferred1"><a name="line263" />263 end
883
+ </span><span class="marked0"><a name="line264" />264 remain = size -out.write(input.read(size))
884
+ </span><span class="marked1"><a name="line265" />265 return :incomplete_body, remain if remain &gt; 0
885
+ </span><span class="inferred0"><a name="line266" />266
886
+ </span><span class="marked1"><a name="line267" />267 line = input.read(2)
887
+ </span><span class="marked0"><a name="line268" />268 if line.nil? or line.length &lt; 2
888
+ </span><span class="uncovered1"><a name="line269" />269 return :incomplete_trailer, line
889
+ </span><span class="marked0"><a name="line270" />270 elsif line != &quot;\r\n&quot;
890
+ </span><span class="uncovered1"><a name="line271" />271 raise HttpClientParserError.new(&quot;invalid chunked encoding trailer&quot;)
891
+ </span><span class="uncovered0"><a name="line272" />272 end
892
+ </span><span class="uncovered1"><a name="line273" />273 end
893
+ </span><span class="uncovered0"><a name="line274" />274 rescue EOFError
894
+ </span><span class="uncovered1"><a name="line275" />275 # this is thrown when the header read is attempted and
895
+ </span><span class="uncovered0"><a name="line276" />276 # there's nothing in the buffer
896
+ </span><span class="uncovered1"><a name="line277" />277 return :eof_error, nil
897
+ </span><span class="uncovered0"><a name="line278" />278 end
898
+ </span><span class="marked1"><a name="line279" />279 end
899
+ </span><span class="inferred0"><a name="line280" />280
900
+ </span><span class="marked1"><a name="line281" />281 def read_chunked_encoding(resp, sock, parser)
901
+ </span><span class="marked0"><a name="line282" />282 out = StringIO.new
902
+ </span><span class="marked1"><a name="line283" />283 input = StringIO.new(resp.http_body)
903
+ </span><span class="inferred0"><a name="line284" />284
904
+ </span><span class="inferred1"><a name="line285" />285 # read from the http body first, then continue at the socket
905
+ </span><span class="marked0"><a name="line286" />286 status, result = read_chunks(input, out, parser)
906
+ </span><span class="marked1"><a name="line287" />287
907
+ </span><span class="marked0"><a name="line288" />288 case status
908
+ </span><span class="marked1"><a name="line289" />289 when :incomplete_trailer
909
+ </span><span class="uncovered0"><a name="line290" />290 if result.nil?
910
+ </span><span class="uncovered1"><a name="line291" />291 sock.read(2)
911
+ </span><span class="uncovered0"><a name="line292" />292 else
912
+ </span><span class="uncovered1"><a name="line293" />293 sock.read(result.length - 2)
913
+ </span><span class="uncovered0"><a name="line294" />294 end
914
+ </span><span class="marked1"><a name="line295" />295 when :incomplete_body
915
+ </span><span class="marked0"><a name="line296" />296 out.write(sock.read(result)) # read the remaining
916
+ </span><span class="marked1"><a name="line297" />297 sock.read(2)
917
+ </span><span class="uncovered0"><a name="line298" />298 when :incomplete_header
918
+ </span><span class="uncovered1"><a name="line299" />299 # push what we read back onto the socket, but backwards
919
+ </span><span class="uncovered0"><a name="line300" />300 result.reverse!
920
+ </span><span class="uncovered1"><a name="line301" />301 result.each_byte {|b| sock.ungetc(b) }
921
+ </span><span class="uncovered0"><a name="line302" />302 when :finished
922
+ </span><span class="uncovered1"><a name="line303" />303 # all done, get out
923
+ </span><span class="uncovered0"><a name="line304" />304 out.rewind; return out.read
924
+ </span><span class="uncovered1"><a name="line305" />305 when :eof_error
925
+ </span><span class="uncovered0"><a name="line306" />306 # read everything we could, ignore
926
+ </span><span class="uncovered1"><a name="line307" />307 end
927
+ </span><span class="inferred0"><a name="line308" />308
928
+ </span><span class="inferred1"><a name="line309" />309 # then continue reading them from the socket
929
+ </span><span class="marked0"><a name="line310" />310 status, result = read_chunks(sock, out, parser)
930
+ </span><span class="marked1"><a name="line311" />311
931
+ </span><span class="inferred0"><a name="line312" />312 # and now the http_body is the chunk
932
+ </span><span class="marked1"><a name="line313" />313 out.rewind; return out.read
933
+ </span><span class="inferred0"><a name="line314" />314 end
934
+ </span><span class="inferred1"><a name="line315" />315
935
+ </span><span class="inferred0"><a name="line316" />316 # Reads an HTTP response from the given socket. It uses
936
+ </span><span class="inferred1"><a name="line317" />317 # readpartial which only appeared in Ruby 1.8.4. The result
937
+ </span><span class="inferred0"><a name="line318" />318 # is a fully formed HttpResponse object for you to play with.
938
+ </span><span class="inferred1"><a name="line319" />319 #
939
+ </span><span class="inferred0"><a name="line320" />320 # As with other methods in this class it doesn't stop any exceptions
940
+ </span><span class="inferred1"><a name="line321" />321 # from reaching your code. It's for experts who want these exceptions
941
+ </span><span class="inferred0"><a name="line322" />322 # so either write a wrapper, use net/http, or deal with it on your end.
942
+ </span><span class="marked1"><a name="line323" />323 def read_response(sock)
943
+ </span><span class="marked0"><a name="line324" />324 data, resp = nil, nil
944
+ </span><span class="marked1"><a name="line325" />325 parser = HttpClientParser.new
945
+ </span><span class="marked0"><a name="line326" />326 resp = HttpResponse.new
946
+ </span><span class="inferred1"><a name="line327" />327
947
+ </span><span class="marked0"><a name="line328" />328 notify :read_header do
948
+ </span><span class="marked1"><a name="line329" />329 data = sock.readpartial(1024)
949
+ </span><span class="marked0"><a name="line330" />330 nread = parser.execute(resp, data, 0)
950
+ </span><span class="inferred1"><a name="line331" />331
951
+ </span><span class="marked0"><a name="line332" />332 while not parser.finished?
952
+ </span><span class="uncovered1"><a name="line333" />333 data += sock.readpartial(1024)
953
+ </span><span class="uncovered0"><a name="line334" />334 nread += parser.execute(resp, data, nread)
954
+ </span><span class="uncovered1"><a name="line335" />335 end
955
+ </span><span class="uncovered0"><a name="line336" />336 end
956
+ </span><span class="inferred1"><a name="line337" />337
957
+ </span><span class="marked0"><a name="line338" />338 notify :read_body do
958
+ </span><span class="marked1"><a name="line339" />339 if resp[TRANSFER_ENCODING] and resp[TRANSFER_ENCODING].index(&quot;chunked&quot;)
959
+ </span><span class="marked0"><a name="line340" />340 resp.http_body = read_chunked_encoding(resp, sock, parser)
960
+ </span><span class="marked1"><a name="line341" />341 elsif resp[CONTENT_LENGTH]
961
+ </span><span class="marked0"><a name="line342" />342 cl = resp[CONTENT_LENGTH].to_i
962
+ </span><span class="marked1"><a name="line343" />343 if cl - resp.http_body.length &gt; 0
963
+ </span><span class="uncovered0"><a name="line344" />344 resp.http_body += sock.read(cl - resp.http_body.length)
964
+ </span><span class="marked1"><a name="line345" />345 elsif cl &lt; resp.http_body.length
965
+ </span><span class="uncovered0"><a name="line346" />346 STDERR.puts &quot;Web site sucks, they said Content-Length: #{cl}, but sent a longer body length: #{resp.http_body.length}&quot;
966
+ </span><span class="uncovered1"><a name="line347" />347 end
967
+ </span><span class="inferred0"><a name="line348" />348 else
968
+ </span><span class="marked1"><a name="line349" />349 resp.http_body += sock.read
969
+ </span><span class="inferred0"><a name="line350" />350 end
970
+ </span><span class="inferred1"><a name="line351" />351 end
971
+ </span><span class="inferred0"><a name="line352" />352
972
+ </span><span class="marked1"><a name="line353" />353 if resp[SET_COOKIE]
973
+ </span><span class="marked0"><a name="line354" />354 cookies = query_parse(resp[SET_COOKIE], ';,')
974
+ </span><span class="marked1"><a name="line355" />355 @cookies.merge! cookies
975
+ </span><span class="marked0"><a name="line356" />356 @cookies.delete &quot;path&quot;
976
+ </span><span class="inferred1"><a name="line357" />357 end
977
+ </span><span class="inferred0"><a name="line358" />358
978
+ </span><span class="marked1"><a name="line359" />359 notify :close do
979
+ </span><span class="marked0"><a name="line360" />360 sock.close
980
+ </span><span class="inferred1"><a name="line361" />361 end
981
+ </span><span class="inferred0"><a name="line362" />362
982
+ </span><span class="marked1"><a name="line363" />363 resp
983
+ </span><span class="inferred0"><a name="line364" />364 end
984
+ </span><span class="inferred1"><a name="line365" />365
985
+ </span><span class="inferred0"><a name="line366" />366 # Does the socket connect and then build_request, read_response
986
+ </span><span class="inferred1"><a name="line367" />367 # calls finally returning the result.
987
+ </span><span class="marked0"><a name="line368" />368 def send_request(method, uri, req)
988
+ </span><span class="marked1"><a name="line369" />369 begin
989
+ </span><span class="marked0"><a name="line370" />370 sock = nil
990
+ </span><span class="marked1"><a name="line371" />371 notify :connect do
991
+ </span><span class="marked0"><a name="line372" />372 sock = TCPSocket.new(@host, @port)
992
+ </span><span class="inferred1"><a name="line373" />373 end
993
+ </span><span class="inferred0"><a name="line374" />374
994
+ </span><span class="marked1"><a name="line375" />375 out = StringIO.new
995
+ </span><span class="marked0"><a name="line376" />376 body = build_request(out, method, uri, req)
996
+ </span><span class="marked1"><a name="line377" />377
997
+ </span><span class="marked0"><a name="line378" />378 notify :send_request do
998
+ </span><span class="marked1"><a name="line379" />379 sock.write(out.string + body)
999
+ </span><span class="marked0"><a name="line380" />380 sock.flush
1000
+ </span><span class="inferred1"><a name="line381" />381 end
1001
+ </span><span class="inferred0"><a name="line382" />382
1002
+ </span><span class="marked1"><a name="line383" />383 return read_response(sock)
1003
+ </span><span class="marked0"><a name="line384" />384 rescue Object
1004
+ </span><span class="marked1"><a name="line385" />385 raise $!
1005
+ </span><span class="inferred0"><a name="line386" />386 ensure
1006
+ </span><span class="marked1"><a name="line387" />387 sock.close unless (!sock or sock.closed?)
1007
+ </span><span class="inferred0"><a name="line388" />388 end
1008
+ </span><span class="marked1"><a name="line389" />389 end
1009
+ </span><span class="inferred0"><a name="line390" />390
1010
+ </span><span class="inferred1"><a name="line391" />391
1011
+ </span><span class="inferred0"><a name="line392" />392 # Translates unknown function calls into PUT, GET, POST, DELETE, HEAD
1012
+ </span><span class="inferred1"><a name="line393" />393 # methods. The allowed HTTP methods allowed are restricted by the
1013
+ </span><span class="inferred0"><a name="line394" />394 # @allowed_methods attribute which you can set after construction or
1014
+ </span><span class="inferred1"><a name="line395" />395 # during construction with :allowed_methods =&gt; [:put, :get, ...]
1015
+ </span><span class="marked0"><a name="line396" />396 def method_missing(symbol, *args)
1016
+ </span><span class="marked1"><a name="line397" />397 if @allowed_methods.include? symbol
1017
+ </span><span class="marked0"><a name="line398" />398 method = symbol.to_s.upcase
1018
+ </span><span class="marked1"><a name="line399" />399 resp = send_request(method, args[0], args[1] || {})
1019
+ </span><span class="marked0"><a name="line400" />400 resp = redirect(symbol, resp) if @redirect
1020
+ </span><span class="marked1"><a name="line401" />401
1021
+ </span><span class="marked0"><a name="line402" />402 return resp
1022
+ </span><span class="inferred1"><a name="line403" />403 else
1023
+ </span><span class="marked0"><a name="line404" />404 raise &quot;Invalid method: #{symbol}&quot;
1024
+ </span><span class="inferred1"><a name="line405" />405 end
1025
+ </span><span class="marked0"><a name="line406" />406 end
1026
+ </span><span class="inferred1"><a name="line407" />407
1027
+ </span><span class="inferred0"><a name="line408" />408 # Keeps doing requests until it doesn't receive a 3XX request.
1028
+ </span><span class="marked1"><a name="line409" />409 def redirect(method, resp, *args)
1029
+ </span><span class="marked0"><a name="line410" />410 @redirect.times do
1030
+ </span><span class="marked1"><a name="line411" />411 break if resp.http_status.index(&quot;3&quot;) != 0
1031
+ </span><span class="inferred0"><a name="line412" />412
1032
+ </span><span class="marked1"><a name="line413" />413 host = encode_host(@host,@port)
1033
+ </span><span class="marked0"><a name="line414" />414 location = resp[LOCATION]
1034
+ </span><span class="inferred1"><a name="line415" />415
1035
+ </span><span class="marked0"><a name="line416" />416 if location.index(host) == 0
1036
+ </span><span class="uncovered1"><a name="line417" />417 # begins with the host so strip that off
1037
+ </span><span class="uncovered0"><a name="line418" />418 location = location[host.length .. -1]
1038
+ </span><span class="uncovered1"><a name="line419" />419 end
1039
+ </span><span class="inferred0"><a name="line420" />420
1040
+ </span><span class="marked1"><a name="line421" />421 @notifier.redirect(:begins) if @notifier
1041
+ </span><span class="marked0"><a name="line422" />422 resp = self.send(method, location, *args)
1042
+ </span><span class="marked1"><a name="line423" />423 @notifier.redirect(:ends) if @notifier
1043
+ </span><span class="inferred0"><a name="line424" />424 end
1044
+ </span><span class="inferred1"><a name="line425" />425
1045
+ </span><span class="marked0"><a name="line426" />426 return resp
1046
+ </span><span class="inferred1"><a name="line427" />427 end
1047
+ </span><span class="inferred0"><a name="line428" />428
1048
+ </span><span class="inferred1"><a name="line429" />429 # Clears out the cookies in use so far in order to get
1049
+ </span><span class="inferred0"><a name="line430" />430 # a clean slate.
1050
+ </span><span class="marked1"><a name="line431" />431 def reset
1051
+ </span><span class="uncovered0"><a name="line432" />432 @cookies.clear
1052
+ </span><span class="uncovered1"><a name="line433" />433 end
1053
+ </span><span class="inferred0"><a name="line434" />434
1054
+ </span><span class="inferred1"><a name="line435" />435
1055
+ </span><span class="inferred0"><a name="line436" />436 # Sends the notifications to the registered notifier, taking
1056
+ </span><span class="inferred1"><a name="line437" />437 # a block that it runs doing the :begins, :ends states
1057
+ </span><span class="inferred0"><a name="line438" />438 # around it.
1058
+ </span><span class="inferred1"><a name="line439" />439 #
1059
+ </span><span class="inferred0"><a name="line440" />440 # It also catches errors transparently in order to call
1060
+ </span><span class="inferred1"><a name="line441" />441 # the notifier when an attempt fails.
1061
+ </span><span class="marked0"><a name="line442" />442 def notify(event)
1062
+ </span><span class="marked1"><a name="line443" />443 @notifier.send(event, :begins) if @notifier
1063
+ </span><span class="marked0"><a name="line444" />444
1064
+ </span><span class="marked1"><a name="line445" />445 begin
1065
+ </span><span class="marked0"><a name="line446" />446 yield
1066
+ </span><span class="marked1"><a name="line447" />447 @notifier.send(event, :ends) if @notifier
1067
+ </span><span class="marked0"><a name="line448" />448 rescue Object
1068
+ </span><span class="marked1"><a name="line449" />449 @notifier.send(event, :error) if @notifier
1069
+ </span><span class="marked0"><a name="line450" />450 raise $!
1070
+ </span><span class="inferred1"><a name="line451" />451 end
1071
+ </span><span class="inferred0"><a name="line452" />452 end
1072
+ </span><span class="inferred1"><a name="line453" />453 end
1073
+ </span><span class="inferred0"><a name="line454" />454
1074
+ </span><span class="inferred1"><a name="line455" />455
1075
+ </span><span class="inferred0"><a name="line456" />456
1076
+ </span><span class="inferred1"><a name="line457" />457 # This simple class can be registered with an HttpClient and it'll
1077
+ </span><span class="inferred0"><a name="line458" />458 # get called when different parts of the HTTP request happen.
1078
+ </span><span class="inferred1"><a name="line459" />459 # Each function represents a different event, and the state parameter
1079
+ </span><span class="inferred0"><a name="line460" />460 # is a symbol of consisting of:
1080
+ </span><span class="inferred1"><a name="line461" />461 #
1081
+ </span><span class="inferred0"><a name="line462" />462 # :begins -- event begins.
1082
+ </span><span class="inferred1"><a name="line463" />463 # :error -- event caused exception.
1083
+ </span><span class="inferred0"><a name="line464" />464 # :ends -- event finished (not called if error).
1084
+ </span><span class="inferred1"><a name="line465" />465 #
1085
+ </span><span class="inferred0"><a name="line466" />466 # These calls are made synchronously so you can throttle
1086
+ </span><span class="inferred1"><a name="line467" />467 # the client by sleeping inside them and can track timing
1087
+ </span><span class="inferred0"><a name="line468" />468 # data.
1088
+ </span><span class="marked1"><a name="line469" />469 class Notifier
1089
+ </span><span class="inferred0"><a name="line470" />470 # Fired right before connecting and right after the connection.
1090
+ </span><span class="marked1"><a name="line471" />471 def connect(state)
1091
+ </span><span class="inferred0"><a name="line472" />472 end
1092
+ </span><span class="inferred1"><a name="line473" />473
1093
+ </span><span class="inferred0"><a name="line474" />474 # Before and after the full request is actually sent. This may
1094
+ </span><span class="inferred1"><a name="line475" />475 # become &quot;send_header&quot; and &quot;send_body&quot;, but right now the whole
1095
+ </span><span class="inferred0"><a name="line476" />476 # blob is shot out in one chunk for efficiency.
1096
+ </span><span class="marked1"><a name="line477" />477 def send_request(state)
1097
+ </span><span class="inferred0"><a name="line478" />478 end
1098
+ </span><span class="inferred1"><a name="line479" />479
1099
+ </span><span class="inferred0"><a name="line480" />480 # Called whenever a HttpClient.redirect is done and there
1100
+ </span><span class="inferred1"><a name="line481" />481 # are redirects to follow. You can use a notifier to detect
1101
+ </span><span class="inferred0"><a name="line482" />482 # that you're doing to many and throw an abort.
1102
+ </span><span class="marked1"><a name="line483" />483 def redirect(state)
1103
+ </span><span class="inferred0"><a name="line484" />484 end
1104
+ </span><span class="inferred1"><a name="line485" />485
1105
+ </span><span class="inferred0"><a name="line486" />486 # Before and after the header is finally read.
1106
+ </span><span class="marked1"><a name="line487" />487 def read_header(state)
1107
+ </span><span class="inferred0"><a name="line488" />488 end
1108
+ </span><span class="inferred1"><a name="line489" />489
1109
+ </span><span class="inferred0"><a name="line490" />490 # Before and after the body is ready.
1110
+ </span><span class="marked1"><a name="line491" />491 def read_body(state)
1111
+ </span><span class="inferred0"><a name="line492" />492 end
1112
+ </span><span class="inferred1"><a name="line493" />493
1113
+ </span><span class="inferred0"><a name="line494" />494 # Before and after the client closes with the server.
1114
+ </span><span class="marked1"><a name="line495" />495 def close(state)
1115
+ </span><span class="inferred0"><a name="line496" />496 end
1116
+ </span><span class="inferred1"><a name="line497" />497 end
1117
+ </span><span class="inferred0"><a name="line498" />498 end
1118
+ </span></pre><hr /> <p>Generated using the <a href='http://eigenclass.org/hiki.rb?rcov'>rcov code coverage analysis tool for Ruby</a> version 0.6.0.</p><p>
1119
+ <a href='http://validator.w3.org/check/referer'>
1120
+ <img src='http://www.w3.org/Icons/valid-xhtml10' height='31' alt='Valid XHTML 1.0!' width='88' />
1121
+ </a>
1122
+ <a href='http://jigsaw.w3.org/css-validator/check/referer'>
1123
+ <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Valid CSS!' style='border:0;width:88px;height:31px' />
1124
+ </a>
1125
+ </p>
1126
+ </body>
1127
+ </html>