http_parser.rb 0.5.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/linux.yml +23 -0
  3. data/.github/workflows/windows.yml +23 -0
  4. data/.gitignore +5 -4
  5. data/.gitmodules +4 -4
  6. data/Gemfile +1 -1
  7. data/README.md +52 -47
  8. data/Rakefile +1 -0
  9. data/bench/standalone.rb +23 -0
  10. data/bench/thin.rb +1 -0
  11. data/ext/ruby_http_parser/extconf.rb +1 -1
  12. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +139 -83
  13. data/ext/ruby_http_parser/ruby_http_parser.c +40 -41
  14. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
  16. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
  17. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1202 -671
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +172 -51
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +8 -3
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  40. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
  41. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
  42. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
  43. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
  44. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +68 -0
  45. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
  46. data/ext/ruby_http_parser/vendor/http-parser/README.md +113 -38
  47. data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
  48. data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
  49. data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
  50. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1576 -780
  51. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +111 -0
  52. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +308 -58
  53. data/ext/ruby_http_parser/vendor/http-parser/test.c +2964 -460
  54. data/http_parser.rb.gemspec +14 -7
  55. data/spec/parser_spec.rb +196 -102
  56. data/spec/support/requests.json +236 -24
  57. data/spec/support/responses.json +202 -36
  58. data/tasks/compile.rake +2 -2
  59. data/tasks/fixtures.rake +8 -2
  60. data/tasks/spec.rake +1 -1
  61. metadata +141 -134
  62. data/Gemfile.lock +0 -32
  63. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  64. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  65. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
  66. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
  67. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
@@ -0,0 +1,68 @@
1
+ # Authors ordered by first contribution.
2
+ Ryan Dahl <ry@tinyclouds.org>
3
+ Jeremy Hinegardner <jeremy@hinegardner.org>
4
+ Sergey Shepelev <temotor@gmail.com>
5
+ Joe Damato <ice799@gmail.com>
6
+ tomika <tomika_nospam@freemail.hu>
7
+ Phoenix Sol <phoenix@burninglabs.com>
8
+ Cliff Frey <cliff@meraki.com>
9
+ Ewen Cheslack-Postava <ewencp@cs.stanford.edu>
10
+ Santiago Gala <sgala@apache.org>
11
+ Tim Becker <tim.becker@syngenio.de>
12
+ Jeff Terrace <jterrace@gmail.com>
13
+ Ben Noordhuis <info@bnoordhuis.nl>
14
+ Nathan Rajlich <nathan@tootallnate.net>
15
+ Mark Nottingham <mnot@mnot.net>
16
+ Aman Gupta <aman@tmm1.net>
17
+ Tim Becker <tim.becker@kuriositaet.de>
18
+ Sean Cunningham <sean.cunningham@mandiant.com>
19
+ Peter Griess <pg@std.in>
20
+ Salman Haq <salman.haq@asti-usa.com>
21
+ Cliff Frey <clifffrey@gmail.com>
22
+ Jon Kolb <jon@b0g.us>
23
+ Fouad Mardini <f.mardini@gmail.com>
24
+ Paul Querna <pquerna@apache.org>
25
+ Felix Geisendörfer <felix@debuggable.com>
26
+ koichik <koichik@improvement.jp>
27
+ Andre Caron <andre.l.caron@gmail.com>
28
+ Ivo Raisr <ivosh@ivosh.net>
29
+ James McLaughlin <jamie@lacewing-project.org>
30
+ David Gwynne <loki@animata.net>
31
+ Thomas LE ROUX <thomas@november-eleven.fr>
32
+ Randy Rizun <rrizun@ortivawireless.com>
33
+ Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
34
+ Simon Zimmermann <simonz05@gmail.com>
35
+ Erik Dubbelboer <erik@dubbelboer.com>
36
+ Martell Malone <martellmalone@gmail.com>
37
+ Bertrand Paquet <bpaquet@octo.com>
38
+ BogDan Vatra <bogdan@kde.org>
39
+ Peter Faiman <peter@thepicard.org>
40
+ Corey Richardson <corey@octayn.net>
41
+ Tóth Tamás <tomika_nospam@freemail.hu>
42
+ Cam Swords <cam.swords@gmail.com>
43
+ Chris Dickinson <christopher.s.dickinson@gmail.com>
44
+ Uli Köhler <ukoehler@btronik.de>
45
+ Charlie Somerville <charlie@charliesomerville.com>
46
+ Patrik Stutz <patrik.stutz@gmail.com>
47
+ Fedor Indutny <fedor.indutny@gmail.com>
48
+ runner <runner.mei@gmail.com>
49
+ Alexis Campailla <alexis@janeasystems.com>
50
+ David Wragg <david@wragg.org>
51
+ Vinnie Falco <vinnie.falco@gmail.com>
52
+ Alex Butum <alexbutum@linux.com>
53
+ Rex Feng <rexfeng@gmail.com>
54
+ Alex Kocharin <alex@kocharin.ru>
55
+ Mark Koopman <markmontymark@yahoo.com>
56
+ Helge Heß <me@helgehess.eu>
57
+ Alexis La Goutte <alexis.lagoutte@gmail.com>
58
+ George Miroshnykov <george.miroshnykov@gmail.com>
59
+ Maciej Małecki <me@mmalecki.com>
60
+ Marc O'Morain <github.com@marcomorain.com>
61
+ Jeff Pinner <jpinner@twitter.com>
62
+ Timothy J Fontaine <tjfontaine@gmail.com>
63
+ Akagi201 <akagi201@gmail.com>
64
+ Romain Giraud <giraud.romain@gmail.com>
65
+ Jay Satiro <raysatiro@yahoo.com>
66
+ Arne Steen <Arne.Steen@gmx.de>
67
+ Kjell Schubert <kjell.schubert@gmail.com>
68
+ Olivier Mengué <dolmen@cpan.org>
@@ -1,4 +1,4 @@
1
- Copyright Joyent, Inc. and other Node contributors. All rights reserved.
1
+ Copyright Joyent, Inc. and other Node contributors.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
@@ -1,6 +1,8 @@
1
1
  HTTP Parser
2
2
  ===========
3
3
 
4
+ [![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser)
5
+
4
6
  This is a parser for HTTP messages written in C. It parses both requests and
5
7
  responses. The parser is designed to be used in performance HTTP
6
8
  applications. It does not make any syscalls nor allocations, it does not
@@ -24,7 +26,7 @@ The parser extracts the following information from HTTP messages:
24
26
  * Response status code
25
27
  * Transfer-Encoding
26
28
  * HTTP version
27
- * Request path, query string, fragment
29
+ * Request URL
28
30
  * Message body
29
31
 
30
32
 
@@ -34,43 +36,46 @@ Usage
34
36
  One `http_parser` object is used per TCP connection. Initialize the struct
35
37
  using `http_parser_init()` and set the callbacks. That might look something
36
38
  like this for a request parser:
39
+ ```c
40
+ http_parser_settings settings;
41
+ settings.on_url = my_url_callback;
42
+ settings.on_header_field = my_header_field_callback;
43
+ /* ... */
37
44
 
38
- http_parser_settings settings;
39
- settings.on_path = my_path_callback;
40
- settings.on_header_field = my_header_field_callback;
41
- /* ... */
42
-
43
- http_parser *parser = malloc(sizeof(http_parser));
44
- http_parser_init(parser, HTTP_REQUEST);
45
- parser->data = my_socket;
45
+ http_parser *parser = malloc(sizeof(http_parser));
46
+ http_parser_init(parser, HTTP_REQUEST);
47
+ parser->data = my_socket;
48
+ ```
46
49
 
47
50
  When data is received on the socket execute the parser and check for errors.
48
51
 
49
- size_t len = 80*1024, nparsed;
50
- char buf[len];
51
- ssize_t recved;
52
+ ```c
53
+ size_t len = 80*1024, nparsed;
54
+ char buf[len];
55
+ ssize_t recved;
52
56
 
53
- recved = recv(fd, buf, len, 0);
57
+ recved = recv(fd, buf, len, 0);
54
58
 
55
- if (recved < 0) {
56
- /* Handle error. */
57
- }
59
+ if (recved < 0) {
60
+ /* Handle error. */
61
+ }
58
62
 
59
- /* Start up / continue the parser.
60
- * Note we pass recved==0 to signal that EOF has been recieved.
61
- */
62
- nparsed = http_parser_execute(parser, &settings, buf, recved);
63
+ /* Start up / continue the parser.
64
+ * Note we pass recved==0 to signal that EOF has been received.
65
+ */
66
+ nparsed = http_parser_execute(parser, &settings, buf, recved);
63
67
 
64
- if (parser->upgrade) {
65
- /* handle new protocol */
66
- } else if (nparsed != recved) {
67
- /* Handle error. Usually just close the connection. */
68
- }
68
+ if (parser->upgrade) {
69
+ /* handle new protocol */
70
+ } else if (nparsed != recved) {
71
+ /* Handle error. Usually just close the connection. */
72
+ }
73
+ ```
69
74
 
70
- HTTP needs to know where the end of the stream is. For example, sometimes
75
+ `http_parser` needs to know where the end of the stream is. For example, sometimes
71
76
  servers send responses without Content-Length and expect the client to
72
- consume input (for the body) until EOF. To tell http_parser about EOF, give
73
- `0` as the forth parameter to `http_parser_execute()`. Callbacks and errors
77
+ consume input (for the body) until EOF. To tell `http_parser` about EOF, give
78
+ `0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
74
79
  can still be encountered during an EOF, so one must still be prepared
75
80
  to receive them.
76
81
 
@@ -88,8 +93,8 @@ the on_body callback.
88
93
  The Special Problem of Upgrade
89
94
  ------------------------------
90
95
 
91
- HTTP supports upgrading the connection to a different protocol. An
92
- increasingly common example of this is the Web Socket protocol which sends
96
+ `http_parser` supports upgrading the connection to a different protocol. An
97
+ increasingly common example of this is the WebSocket protocol which sends
93
98
  a request like
94
99
 
95
100
  GET /demo HTTP/1.1
@@ -101,11 +106,11 @@ a request like
101
106
 
102
107
  followed by non-HTTP data.
103
108
 
104
- (See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more
105
- information the Web Socket protocol.)
109
+ (See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the
110
+ WebSocket protocol.)
106
111
 
107
112
  To support this, the parser will treat this as a normal HTTP message without a
108
- body. Issuing both on_headers_complete and on_message_complete callbacks. However
113
+ body, issuing both on_headers_complete and on_message_complete callbacks. However
109
114
  http_parser_execute() will stop parsing at the end of the headers and return.
110
115
 
111
116
  The user is expected to check if `parser->upgrade` has been set to 1 after
@@ -126,21 +131,84 @@ There are two types of callbacks:
126
131
  * notification `typedef int (*http_cb) (http_parser*);`
127
132
  Callbacks: on_message_begin, on_headers_complete, on_message_complete.
128
133
  * data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
129
- Callbacks: (requests only) on_path, on_query_string, on_uri, on_fragment,
134
+ Callbacks: (requests only) on_url,
130
135
  (common) on_header_field, on_header_value, on_body;
131
136
 
132
137
  Callbacks must return 0 on success. Returning a non-zero value indicates
133
138
  error to the parser, making it exit immediately.
134
139
 
140
+ For cases where it is necessary to pass local information to/from a callback,
141
+ the `http_parser` object's `data` field can be used.
142
+ An example of such a case is when using threads to handle a socket connection,
143
+ parse a request, and then give a response over that socket. By instantiation
144
+ of a thread-local struct containing relevant data (e.g. accepted socket,
145
+ allocated memory for callbacks to write into, etc), a parser's callbacks are
146
+ able to communicate data between the scope of the thread and the scope of the
147
+ callback in a threadsafe manner. This allows `http_parser` to be used in
148
+ multi-threaded contexts.
149
+
150
+ Example:
151
+ ```c
152
+ typedef struct {
153
+ socket_t sock;
154
+ void* buffer;
155
+ int buf_len;
156
+ } custom_data_t;
157
+
158
+
159
+ int my_url_callback(http_parser* parser, const char *at, size_t length) {
160
+ /* access to thread local custom_data_t struct.
161
+ Use this access save parsed data for later use into thread local
162
+ buffer, or communicate over socket
163
+ */
164
+ parser->data;
165
+ ...
166
+ return 0;
167
+ }
168
+
169
+ ...
170
+
171
+ void http_parser_thread(socket_t sock) {
172
+ int nparsed = 0;
173
+ /* allocate memory for user data */
174
+ custom_data_t *my_data = malloc(sizeof(custom_data_t));
175
+
176
+ /* some information for use by callbacks.
177
+ * achieves thread -> callback information flow */
178
+ my_data->sock = sock;
179
+
180
+ /* instantiate a thread-local parser */
181
+ http_parser *parser = malloc(sizeof(http_parser));
182
+ http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
183
+ /* this custom data reference is accessible through the reference to the
184
+ parser supplied to callback functions */
185
+ parser->data = my_data;
186
+
187
+ http_parser_settings settings; /* set up callbacks */
188
+ settings.on_url = my_url_callback;
189
+
190
+ /* execute parser */
191
+ nparsed = http_parser_execute(parser, &settings, buf, recved);
192
+
193
+ ...
194
+ /* parsed information copied from callback.
195
+ can now perform action on data copied into thread-local memory from callbacks.
196
+ achieves callback -> thread information flow */
197
+ my_data->buffer;
198
+ ...
199
+ }
200
+
201
+ ```
202
+
135
203
  In case you parse HTTP message in chunks (i.e. `read()` request line
136
204
  from socket, parse, read half headers, parse, etc) your data callbacks
137
- may be called more than once. Http-parser guarantees that data pointer is only
205
+ may be called more than once. `http_parser` guarantees that data pointer is only
138
206
  valid for the lifetime of callback. You can also `read()` into a heap allocated
139
207
  buffer to avoid copying memory around if this fits your application.
140
208
 
141
209
  Reading headers may be a tricky task if you read/parse headers partially.
142
210
  Basically, you need to remember whether last header callback was field or value
143
- and apply following logic:
211
+ and apply the following logic:
144
212
 
145
213
  (on_header_field and on_header_value shortened to on_h_*)
146
214
  ------------------------ ------------ --------------------------------------------
@@ -164,8 +232,15 @@ and apply following logic:
164
232
  ------------------------ ------------ --------------------------------------------
165
233
 
166
234
 
235
+ Parsing URLs
236
+ ------------
237
+
238
+ A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
239
+ Users of this library may wish to use it to parse URLs constructed from
240
+ consecutive `on_url` callbacks.
241
+
167
242
  See examples of reading in headers:
168
243
 
169
244
  * [partial example](http://gist.github.com/155877) in C
170
- * [from http-parser tests](http://github.com/ry/http-parser/blob/37a0ff8928fb0d83cec0d0d8909c5a4abcd221af/test.c#L403) in C
171
- * [from Node library](http://github.com/ry/node/blob/842eaf446d2fdcb33b296c67c911c32a0dabc747/src/http.js#L284) in Javascript
245
+ * [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
246
+ * [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript
@@ -0,0 +1,128 @@
1
+ /* Copyright Fedor Indutny. All rights reserved.
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to
5
+ * deal in the Software without restriction, including without limitation the
6
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ * sell copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ * IN THE SOFTWARE.
20
+ */
21
+ #include "http_parser.h"
22
+ #include <assert.h>
23
+ #include <stdint.h>
24
+ #include <stdio.h>
25
+ #include <string.h>
26
+ #include <sys/time.h>
27
+
28
+ /* 8 gb */
29
+ static const int64_t kBytes = 8LL << 30;
30
+
31
+ static const char data[] =
32
+ "POST /joyent/http-parser HTTP/1.1\r\n"
33
+ "Host: github.com\r\n"
34
+ "DNT: 1\r\n"
35
+ "Accept-Encoding: gzip, deflate, sdch\r\n"
36
+ "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\r\n"
37
+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) "
38
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
39
+ "Chrome/39.0.2171.65 Safari/537.36\r\n"
40
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,"
41
+ "image/webp,*/*;q=0.8\r\n"
42
+ "Referer: https://github.com/joyent/http-parser\r\n"
43
+ "Connection: keep-alive\r\n"
44
+ "Transfer-Encoding: chunked\r\n"
45
+ "Cache-Control: max-age=0\r\n\r\nb\r\nhello world\r\n0\r\n";
46
+ static const size_t data_len = sizeof(data) - 1;
47
+
48
+ static int on_info(http_parser* p) {
49
+ return 0;
50
+ }
51
+
52
+
53
+ static int on_data(http_parser* p, const char *at, size_t length) {
54
+ return 0;
55
+ }
56
+
57
+ static http_parser_settings settings = {
58
+ .on_message_begin = on_info,
59
+ .on_headers_complete = on_info,
60
+ .on_message_complete = on_info,
61
+ .on_header_field = on_data,
62
+ .on_header_value = on_data,
63
+ .on_url = on_data,
64
+ .on_status = on_data,
65
+ .on_body = on_data
66
+ };
67
+
68
+ int bench(int iter_count, int silent) {
69
+ struct http_parser parser;
70
+ int i;
71
+ int err;
72
+ struct timeval start;
73
+ struct timeval end;
74
+
75
+ if (!silent) {
76
+ err = gettimeofday(&start, NULL);
77
+ assert(err == 0);
78
+ }
79
+
80
+ fprintf(stderr, "req_len=%d\n", (int) data_len);
81
+ for (i = 0; i < iter_count; i++) {
82
+ size_t parsed;
83
+ http_parser_init(&parser, HTTP_REQUEST);
84
+
85
+ parsed = http_parser_execute(&parser, &settings, data, data_len);
86
+ assert(parsed == data_len);
87
+ }
88
+
89
+ if (!silent) {
90
+ double elapsed;
91
+ double bw;
92
+ double total;
93
+
94
+ err = gettimeofday(&end, NULL);
95
+ assert(err == 0);
96
+
97
+ fprintf(stdout, "Benchmark result:\n");
98
+
99
+ elapsed = (double) (end.tv_sec - start.tv_sec) +
100
+ (end.tv_usec - start.tv_usec) * 1e-6f;
101
+
102
+ total = (double) iter_count * data_len;
103
+ bw = (double) total / elapsed;
104
+
105
+ fprintf(stdout, "%.2f mb | %.2f mb/s | %.2f req/sec | %.2f s\n",
106
+ (double) total / (1024 * 1024),
107
+ bw / (1024 * 1024),
108
+ (double) iter_count / elapsed,
109
+ elapsed);
110
+
111
+ fflush(stdout);
112
+ }
113
+
114
+ return 0;
115
+ }
116
+
117
+ int main(int argc, char** argv) {
118
+ int64_t iterations;
119
+
120
+ iterations = kBytes / (int64_t) data_len;
121
+ if (argc == 2 && strcmp(argv[1], "infinite") == 0) {
122
+ for (;;)
123
+ bench(iterations, 1);
124
+ return 0;
125
+ } else {
126
+ return bench(iterations, 0);
127
+ }
128
+ }
@@ -0,0 +1,157 @@
1
+ /* Copyright Joyent, Inc. and other Node contributors.
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to
5
+ * deal in the Software without restriction, including without limitation the
6
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ * sell copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ * IN THE SOFTWARE.
20
+ */
21
+
22
+ /* Dump what the parser finds to stdout as it happen */
23
+
24
+ #include "http_parser.h"
25
+ #include <stdio.h>
26
+ #include <stdlib.h>
27
+ #include <string.h>
28
+
29
+ int on_message_begin(http_parser* _) {
30
+ (void)_;
31
+ printf("\n***MESSAGE BEGIN***\n\n");
32
+ return 0;
33
+ }
34
+
35
+ int on_headers_complete(http_parser* _) {
36
+ (void)_;
37
+ printf("\n***HEADERS COMPLETE***\n\n");
38
+ return 0;
39
+ }
40
+
41
+ int on_message_complete(http_parser* _) {
42
+ (void)_;
43
+ printf("\n***MESSAGE COMPLETE***\n\n");
44
+ return 0;
45
+ }
46
+
47
+ int on_url(http_parser* _, const char* at, size_t length) {
48
+ (void)_;
49
+ printf("Url: %.*s\n", (int)length, at);
50
+ return 0;
51
+ }
52
+
53
+ int on_header_field(http_parser* _, const char* at, size_t length) {
54
+ (void)_;
55
+ printf("Header field: %.*s\n", (int)length, at);
56
+ return 0;
57
+ }
58
+
59
+ int on_header_value(http_parser* _, const char* at, size_t length) {
60
+ (void)_;
61
+ printf("Header value: %.*s\n", (int)length, at);
62
+ return 0;
63
+ }
64
+
65
+ int on_body(http_parser* _, const char* at, size_t length) {
66
+ (void)_;
67
+ printf("Body: %.*s\n", (int)length, at);
68
+ return 0;
69
+ }
70
+
71
+ void usage(const char* name) {
72
+ fprintf(stderr,
73
+ "Usage: %s $type $filename\n"
74
+ " type: -x, where x is one of {r,b,q}\n"
75
+ " parses file as a Response, reQuest, or Both\n",
76
+ name);
77
+ exit(EXIT_FAILURE);
78
+ }
79
+
80
+ int main(int argc, char* argv[]) {
81
+ enum http_parser_type file_type;
82
+
83
+ if (argc != 3) {
84
+ usage(argv[0]);
85
+ }
86
+
87
+ char* type = argv[1];
88
+ if (type[0] != '-') {
89
+ usage(argv[0]);
90
+ }
91
+
92
+ switch (type[1]) {
93
+ /* in the case of "-", type[1] will be NUL */
94
+ case 'r':
95
+ file_type = HTTP_RESPONSE;
96
+ break;
97
+ case 'q':
98
+ file_type = HTTP_REQUEST;
99
+ break;
100
+ case 'b':
101
+ file_type = HTTP_BOTH;
102
+ break;
103
+ default:
104
+ usage(argv[0]);
105
+ }
106
+
107
+ char* filename = argv[2];
108
+ FILE* file = fopen(filename, "r");
109
+ if (file == NULL) {
110
+ perror("fopen");
111
+ goto fail;
112
+ }
113
+
114
+ fseek(file, 0, SEEK_END);
115
+ long file_length = ftell(file);
116
+ if (file_length == -1) {
117
+ perror("ftell");
118
+ goto fail;
119
+ }
120
+ fseek(file, 0, SEEK_SET);
121
+
122
+ char* data = malloc(file_length);
123
+ if (fread(data, 1, file_length, file) != (size_t)file_length) {
124
+ fprintf(stderr, "couldn't read entire file\n");
125
+ free(data);
126
+ goto fail;
127
+ }
128
+
129
+ http_parser_settings settings;
130
+ memset(&settings, 0, sizeof(settings));
131
+ settings.on_message_begin = on_message_begin;
132
+ settings.on_url = on_url;
133
+ settings.on_header_field = on_header_field;
134
+ settings.on_header_value = on_header_value;
135
+ settings.on_headers_complete = on_headers_complete;
136
+ settings.on_body = on_body;
137
+ settings.on_message_complete = on_message_complete;
138
+
139
+ http_parser parser;
140
+ http_parser_init(&parser, file_type);
141
+ size_t nparsed = http_parser_execute(&parser, &settings, data, file_length);
142
+ free(data);
143
+
144
+ if (nparsed != (size_t)file_length) {
145
+ fprintf(stderr,
146
+ "Error: %s (%s)\n",
147
+ http_errno_description(HTTP_PARSER_ERRNO(&parser)),
148
+ http_errno_name(HTTP_PARSER_ERRNO(&parser)));
149
+ goto fail;
150
+ }
151
+
152
+ return EXIT_SUCCESS;
153
+
154
+ fail:
155
+ fclose(file);
156
+ return EXIT_FAILURE;
157
+ }