http_parser.rb 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MGMxN2Q5N2MzMTlmNjEyY2NhMmQzNjdjMDRiYmQxNGY4ZjIyMzM0Mg==
5
- data.tar.gz: !binary |-
6
- YmVhZTVjYmMxNGM3YjUwOWQ3NmUwYzEwZThlZWM5NDQ0ZGMwYTgwNA==
2
+ SHA256:
3
+ metadata.gz: afdb28464ccb0f753a1d66be02b667683d6aadfe31fe03a88f889252b457761d
4
+ data.tar.gz: 6041b3dc3f212160ae00b72b193e4620c5facd59096a28b122c0ef5a901dc80b
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- YWM3ZDZmMjdmYzQxMTZiN2VjZTMxYjczMjgxN2ZjYWY0YjE3ODllYjM5Nzg0
10
- OTUwOTk3ODYwZGJhNGIwMjA0Mjg1MTFkNDgxY2ZlMGIzZjQwNmQ1ODVkMjFj
11
- ZjQyYzVmNjlkYTQ0NDZkMzhhYjE1M2FhZTdiOTdlYzAxMzljOWY=
12
- data.tar.gz: !binary |-
13
- M2ZiYTcwYTg2ZDJjZDc2N2Y0NzhmMzE0MzExNTY5M2I3MzAxMTkzNzUyYzUz
14
- NGM2YzRmOGM3OGQ4NDNkMmIwYjM2MjYyMGJlNTU1MTVlNzFiYjgxZjJiYmNi
15
- Y2Q4N2YyZWFjODYwYzlhNGMwMzcxNTcwZjIwMWJjNDViNjQ1MTc=
6
+ metadata.gz: 41249c628f931cd9721e32bd378a44b8e49b25706b491ae3761d641e55bac1205afe9d3d02d88d5b4f3161adee4a65416c5eec2a51fcacad1b050d6f6d2637fc
7
+ data.tar.gz: ae5718390cce25d2ee7fcbaf923fac015189079b64ea2f37759c41ee2e7f2714dafaf6bf37ed6434f540e82e87c6a13723e226ac27000d1f0e2d7b2681643514
@@ -0,0 +1,23 @@
1
+ name: Testing on Ubuntu
2
+ on:
3
+ - push
4
+ - pull_request
5
+ jobs:
6
+ build:
7
+ runs-on: ${{ matrix.os }}
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby: [ '2.6', '2.7', '3.0' ]
12
+ os: [ 'ubuntu-latest' ]
13
+ name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: unit testing
20
+ run: |
21
+ gem install bundler rake
22
+ bundle install --jobs 4 --retry 3
23
+ bundle exec rake
@@ -0,0 +1,23 @@
1
+ name: Testing on Windows
2
+ on:
3
+ - push
4
+ - pull_request
5
+ jobs:
6
+ build:
7
+ runs-on: ${{ matrix.os }}
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby: [ '2.6', '2.7', '3.0' ]
12
+ os: [ 'windows-latest' ]
13
+ name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: unit testing
20
+ run: |
21
+ gem install bundler rake
22
+ bundle install --jobs 4 --retry 3
23
+ bundle exec rake
data/.gitignore CHANGED
@@ -1,11 +1,12 @@
1
- tmp
1
+ *.bundle
2
2
  *.bundle
3
3
  *.gem
4
+ *.jar
4
5
  *.o
6
+ *.rbc
5
7
  *.so
6
- *.bundle
7
- *.jar
8
8
  *.swp
9
+ Gemfile.lock
9
10
  Makefile
10
11
  tags
11
- *.rbc
12
+ tmp
data/.gitmodules CHANGED
@@ -1,6 +1,6 @@
1
1
  [submodule "http-parser"]
2
2
  path = ext/ruby_http_parser/vendor/http-parser
3
- url = git://github.com/joyent/http-parser.git
3
+ url = https://github.com/nodejs/http-parser.git
4
4
  [submodule "http-parser-java"]
5
5
  path = ext/ruby_http_parser/vendor/http-parser-java
6
- url = git://github.com/tmm1/http-parser.java
6
+ url = https://github.com/tmm1/http-parser.java
data/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  A simple callback-based HTTP request/response parser for writing http
4
4
  servers, clients and proxies.
5
5
 
6
- This gem is built on top of [joyent/http-parser](http://github.com/joyent/http-parser) and its java port [http-parser/http-parser.java](http://github.com/http-parser/http-parser.java).
6
+ This gem is built on top of [joyent/http-parser](https://github.com/joyent/http-parser) and its java port [http-parser/http-parser.java](https://github.com/http-parser/http-parser.java).
7
7
 
8
8
  ## Supported Platforms
9
9
 
10
10
  This gem aims to work on all major Ruby platforms, including:
11
11
 
12
- - MRI 1.8 and 1.9
12
+ - MRI 1.8, 1.9 and 2.0; should work on MRI 2.4+
13
13
  - Rubinius
14
14
  - JRuby
15
15
  - win32
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  # load tasks
2
+ require 'bundler/gem_tasks'
2
3
  Dir['tasks/*.rake'].sort.each { |f| load f }
3
4
 
4
5
  # default task
@@ -18,7 +18,7 @@ src_dir = File.expand_path('../', __FILE__)
18
18
  }
19
19
  end
20
20
 
21
- $CFLAGS << " -I#{src_dir}"
21
+ $CFLAGS << " -I\"#{src_dir}\""
22
22
 
23
23
  dir_config("ruby_http_parser")
24
24
  create_makefile("ruby_http_parser")
@@ -64,6 +64,7 @@ public class RubyHttpParser extends RubyObject {
64
64
  private IRubyObject on_body;
65
65
  private IRubyObject on_message_complete;
66
66
 
67
+ private IRubyObject status;
67
68
  private IRubyObject requestUrl;
68
69
  private IRubyObject requestPath;
69
70
  private IRubyObject queryString;
@@ -106,6 +107,18 @@ public class RubyHttpParser extends RubyObject {
106
107
  private void initSettings() {
107
108
  this.settings = new ParserSettings();
108
109
 
110
+ this.settings.on_status = new HTTPDataCallback() {
111
+ public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
112
+ byte[] data = fetchBytes(buf, pos, len);
113
+ if (runtime.is1_9() || runtime.is2_0()) {
114
+ ((RubyString) status).cat(data, 0, data.length, UTF8);
115
+ } else {
116
+ ((RubyString) status).cat(data);
117
+ }
118
+ return 0;
119
+ }
120
+ };
121
+
109
122
  this.settings.on_url = new HTTPDataCallback() {
110
123
  public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
111
124
  byte[] data = fetchBytes(buf, pos, len);
@@ -202,12 +215,14 @@ public class RubyHttpParser extends RubyObject {
202
215
  headers = new RubyHash(runtime);
203
216
 
204
217
  if (runtime.is1_9() || runtime.is2_0()) {
218
+ status = RubyString.newEmptyString(runtime, UTF8);
205
219
  requestUrl = RubyString.newEmptyString(runtime, UTF8);
206
220
  requestPath = RubyString.newEmptyString(runtime, UTF8);
207
221
  queryString = RubyString.newEmptyString(runtime, UTF8);
208
222
  fragment = RubyString.newEmptyString(runtime, UTF8);
209
223
  upgradeData = RubyString.newEmptyString(runtime, UTF8);
210
224
  } else {
225
+ status = RubyString.newEmptyString(runtime);
211
226
  requestUrl = RubyString.newEmptyString(runtime);
212
227
  requestPath = RubyString.newEmptyString(runtime);
213
228
  queryString = RubyString.newEmptyString(runtime);
@@ -309,7 +324,8 @@ public class RubyHttpParser extends RubyObject {
309
324
  this.parser = new HTTPParser();
310
325
  this.parser.HTTP_PARSER_STRICT = true;
311
326
  this.headers = null;
312
-
327
+
328
+ this.status = runtime.getNil();
313
329
  this.requestUrl = runtime.getNil();
314
330
  this.requestPath = runtime.getNil();
315
331
  this.queryString = runtime.getNil();
@@ -446,6 +462,11 @@ public class RubyHttpParser extends RubyObject {
446
462
  return headers == null ? runtime.getNil() : headers;
447
463
  }
448
464
 
465
+ @JRubyMethod(name = "status")
466
+ public IRubyObject getStatus() {
467
+ return status == null ? runtime.getNil() : status;
468
+ }
469
+
449
470
  @JRubyMethod(name = "request_url")
450
471
  public IRubyObject getRequestUrl() {
451
472
  return requestUrl == null ? runtime.getNil() : requestUrl;
@@ -16,6 +16,7 @@
16
16
  typedef struct ParserWrapper {
17
17
  ryah_http_parser parser;
18
18
 
19
+ VALUE status;
19
20
  VALUE request_url;
20
21
 
21
22
  VALUE headers;
@@ -45,6 +46,7 @@ void ParserWrapper_init(ParserWrapper *wrapper) {
45
46
  wrapper->parser.http_major = 0;
46
47
  wrapper->parser.http_minor = 0;
47
48
 
49
+ wrapper->status = Qnil;
48
50
  wrapper->request_url = Qnil;
49
51
 
50
52
  wrapper->upgrade_data = Qnil;
@@ -59,6 +61,7 @@ void ParserWrapper_init(ParserWrapper *wrapper) {
59
61
  void ParserWrapper_mark(void *data) {
60
62
  if(data) {
61
63
  ParserWrapper *wrapper = (ParserWrapper *) data;
64
+ rb_gc_mark_maybe(wrapper->status);
62
65
  rb_gc_mark_maybe(wrapper->request_url);
63
66
  rb_gc_mark_maybe(wrapper->upgrade_data);
64
67
  rb_gc_mark_maybe(wrapper->headers);
@@ -101,6 +104,7 @@ static VALUE Smixed;
101
104
  int on_message_begin(ryah_http_parser *parser) {
102
105
  GET_WRAPPER(wrapper, parser);
103
106
 
107
+ wrapper->status = rb_str_new2("");
104
108
  wrapper->request_url = rb_str_new2("");
105
109
  wrapper->headers = rb_hash_new();
106
110
  wrapper->upgrade_data = rb_str_new2("");
@@ -121,9 +125,28 @@ int on_message_begin(ryah_http_parser *parser) {
121
125
  }
122
126
  }
123
127
 
128
+ int on_status(ryah_http_parser *parser, const char *at, size_t length) {
129
+ GET_WRAPPER(wrapper, parser);
130
+
131
+ if (at && length) {
132
+ if (wrapper->status == Qnil) {
133
+ wrapper->status = rb_str_new(at, length);
134
+ } else {
135
+ rb_str_cat(wrapper->status, at, length);
136
+ }
137
+ }
138
+ return 0;
139
+ }
140
+
124
141
  int on_url(ryah_http_parser *parser, const char *at, size_t length) {
125
142
  GET_WRAPPER(wrapper, parser);
126
- rb_str_cat(wrapper->request_url, at, length);
143
+ if (at && length) {
144
+ if (wrapper->request_url == Qnil) {
145
+ wrapper->request_url = rb_str_new(at, length);
146
+ } else {
147
+ rb_str_cat(wrapper->request_url, at, length);
148
+ }
149
+ }
127
150
  return 0;
128
151
  }
129
152
 
@@ -136,7 +159,6 @@ int on_header_field(ryah_http_parser *parser, const char *at, size_t length) {
136
159
  } else {
137
160
  rb_str_cat(wrapper->curr_field_name, at, length);
138
161
  }
139
-
140
162
  return 0;
141
163
  }
142
164
 
@@ -248,6 +270,7 @@ int on_message_complete(ryah_http_parser *parser) {
248
270
 
249
271
  static ryah_http_parser_settings settings = {
250
272
  .on_message_begin = on_message_begin,
273
+ .on_status = on_status,
251
274
  .on_url = on_url,
252
275
  .on_header_field = on_header_field,
253
276
  .on_header_value = on_header_value,
@@ -320,11 +343,12 @@ VALUE Parser_execute(VALUE self, VALUE data) {
320
343
  size_t nparsed = ryah_http_parser_execute(&wrapper->parser, &settings, ptr, len);
321
344
 
322
345
  if (wrapper->parser.upgrade) {
323
- if (RTEST(wrapper->stopped))
346
+ if (RTEST(wrapper->stopped) && !RTEST(wrapper->completed))
324
347
  nparsed += 1;
325
348
 
326
- rb_str_cat(wrapper->upgrade_data, ptr + nparsed, len - nparsed);
327
-
349
+ if (nparsed < len)
350
+ rb_str_cat(wrapper->upgrade_data, ptr + nparsed, len - nparsed);
351
+
328
352
  } else if (nparsed != (size_t)len) {
329
353
  if (!RTEST(wrapper->stopped) && !RTEST(wrapper->completed))
330
354
  rb_raise(eParserError, "Could not parse data entirely (%zu != %zu)", nparsed, len);
@@ -438,6 +462,7 @@ VALUE Parser_status_code(VALUE self) {
438
462
  return wrapper->name; \
439
463
  }
440
464
 
465
+ DEFINE_GETTER(status);
441
466
  DEFINE_GETTER(request_url);
442
467
  DEFINE_GETTER(headers);
443
468
  DEFINE_GETTER(upgrade_data);
@@ -505,6 +530,7 @@ void Init_ruby_http_parser() {
505
530
  rb_define_method(cParser, "http_method", Parser_http_method, 0);
506
531
  rb_define_method(cParser, "status_code", Parser_status_code, 0);
507
532
 
533
+ rb_define_method(cParser, "status", Parser_status, 0);
508
534
  rb_define_method(cParser, "request_url", Parser_request_url, 0);
509
535
  rb_define_method(cParser, "headers", Parser_headers, 0);
510
536
  rb_define_method(cParser, "upgrade_data", Parser_upgrade_data, 0);
@@ -28,5 +28,41 @@ Andre Caron <andre.l.caron@gmail.com>
28
28
  Ivo Raisr <ivosh@ivosh.net>
29
29
  James McLaughlin <jamie@lacewing-project.org>
30
30
  David Gwynne <loki@animata.net>
31
- LE ROUX Thomas <thomas@procheo.fr>
31
+ Thomas LE ROUX <thomas@november-eleven.fr>
32
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,8 +1,4 @@
1
- http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
2
- Igor Sysoev.
3
-
4
- Additional changes are licensed under the same terms as NGINX and
5
- copyright Joyent, Inc. and other Node contributors. All rights reserved.
1
+ Copyright Joyent, Inc. and other Node contributors.
6
2
 
7
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
8
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
@@ -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_uri,
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
  ------------------------ ------------ --------------------------------------------
@@ -174,5 +242,5 @@ consecutive `on_url` callbacks.
174
242
  See examples of reading in headers:
175
243
 
176
244
  * [partial example](http://gist.github.com/155877) in C
177
- * [from http-parser tests](http://github.com/ry/http-parser/blob/37a0ff8928fb0d83cec0d0d8909c5a4abcd221af/test.c#L403) in C
178
- * [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