ebb 0.0.2 → 0.0.3

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.
@@ -17,6 +17,7 @@ typedef void (*field_cb)(void *data, const char *field, size_t flen, const char
17
17
 
18
18
  typedef struct http_parser {
19
19
  int cs;
20
+ int overflow_error;
20
21
  size_t body_start;
21
22
  int content_len;
22
23
  size_t nread;
@@ -36,10 +37,9 @@ typedef struct http_parser {
36
37
  element_cb http_version;
37
38
  element_cb header_done;
38
39
  element_cb content_length;
39
-
40
40
  } http_parser;
41
41
 
42
- int http_parser_init(http_parser *parser);
42
+ void http_parser_init(http_parser *parser);
43
43
  int http_parser_finish(http_parser *parser);
44
44
  size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
45
45
  int http_parser_has_error(http_parser *parser);
@@ -1,13 +1,17 @@
1
1
  require File.dirname(__FILE__) + '/../ruby_lib/ebb'
2
2
  require 'test/unit'
3
3
  require 'net/http'
4
- require 'base64'
4
+ require 'socket'
5
+ require 'rubygems'
6
+ require 'json'
5
7
 
8
+ PORT = 4044
6
9
 
7
10
  class EbbTest < Test::Unit::TestCase
8
11
  def setup
9
12
  @pid = fork do
10
- server = Ebb::Server.new(self, :port => 4044)
13
+ server = Ebb::Server.new(self, :port => PORT)
14
+ STDOUT.reopen "/dev/null", "a"
11
15
  server.start
12
16
  end
13
17
  sleep 0.5
@@ -19,11 +23,11 @@ class EbbTest < Test::Unit::TestCase
19
23
  end
20
24
 
21
25
  def get(path)
22
- Net::HTTP.get_response(URI.parse("http://0.0.0.0:4044#{path}"))
26
+ Net::HTTP.get_response(URI.parse("http://0.0.0.0:#{PORT}#{path}"))
23
27
  end
24
28
 
25
29
  def post(path, data)
26
- Net::HTTP.post_form(URI.parse("http://0.0.0.0:4044#{path}"), data)
30
+ Net::HTTP.post_form(URI.parse("http://0.0.0.0:#{PORT}#{path}"), data)
27
31
  end
28
32
 
29
33
  @@responses = {}
@@ -35,12 +39,6 @@ class EbbTest < Test::Unit::TestCase
35
39
  raise "bytes called with n <= 0" if n <= 0
36
40
  body = @@responses[n] || "C"*n
37
41
  status = 200
38
-
39
- elsif commands.include?('env')
40
- env.delete('rack.input') # delete this because it's hard to marshal
41
- env.delete('rack.errors')
42
- body = Base64.encode64(Marshal.dump(env))
43
- status = 200
44
42
 
45
43
  elsif commands.include?('test_post_length')
46
44
  input_body = ""
@@ -89,7 +87,7 @@ class EbbTest < Test::Unit::TestCase
89
87
 
90
88
  # this is rough but does detect major problems
91
89
  def test_ab
92
- r = %x{ab -n 1000 -c 50 -q http://0.0.0.0:4044/bytes/123}
90
+ r = %x{ab -n 1000 -c 50 -q http://0.0.0.0:#{PORT}/bytes/123}
93
91
  assert r =~ /Requests per second:\s*(\d+)/, r
94
92
  assert $1.to_i > 100, r
95
93
  end
@@ -100,29 +98,84 @@ class EbbTest < Test::Unit::TestCase
100
98
  assert_equal 200, response.code.to_i, response.body
101
99
  end
102
100
  end
101
+ end
102
+
103
+ class EnvTest < Test::Unit::TestCase
104
+ def call(env)
105
+ env.delete('rack.input')
106
+ env.delete('rack.errors')
107
+ [200, {'Content-Type' => 'text/json'}, env.to_json]
108
+ end
103
109
 
104
- def test_env
105
- response = get('/env')
106
- env = Marshal.load(Base64.decode64(response.body))
107
- assert_equal '/env', env['PATH_INFO']
108
- assert_equal '/env', env['REQUEST_PATH']
110
+ def setup
111
+ @pid = fork do
112
+ server = Ebb::Server.new(self, :port => PORT)
113
+ STDOUT.reopen "/dev/null", "a"
114
+ server.start
115
+ end
116
+ sleep 0.5
117
+ end
118
+
119
+ def teardown
120
+ Process.kill('KILL', @pid)
121
+ sleep 0.5
122
+ end
123
+
124
+
125
+ ### Tests from Mongrel http11
126
+
127
+ def request(request_string)
128
+ socket = TCPSocket.new("0.0.0.0", PORT)
129
+ socket.write(request_string)
130
+ lines = []
131
+ socket.read(500000).each_line { |l| lines << l }
132
+ env = JSON.parse(lines.last)
133
+ end
134
+
135
+ def assert_drops_connection(request_string)
136
+ socket = TCPSocket.new("0.0.0.0", PORT)
137
+ socket.write(request_string)
138
+ assert socket.closed?
139
+ end
140
+
141
+
142
+ def test_parse_simple
143
+ env = request("GET / HTTP/1.1\r\n\r\n")
109
144
  assert_equal 'HTTP/1.1', env['SERVER_PROTOCOL']
145
+ assert_equal '/', env['REQUEST_PATH']
146
+ assert_equal 'HTTP/1.1', env['HTTP_VERSION']
147
+ assert_equal '/', env['REQUEST_URI']
110
148
  assert_equal 'CGI/1.2', env['GATEWAY_INTERFACE']
111
- assert_equal '0.0.0.0', env['SERVER_NAME']
112
- assert_equal '4044', env['SERVER_PORT']
113
- assert_equal 'GET', env['REQUEST_METHOD']
149
+ assert_equal 'GET', env['REQUEST_METHOD']
150
+ assert_nil env['FRAGMENT']
151
+ assert_nil env['QUERY_STRING']
114
152
  end
115
153
  end
116
154
 
155
+
117
156
  class EbbRailsTest < Test::Unit::TestCase
118
157
  # just to make sure there isn't some load error
119
158
  def test_ebb_rails_version
120
159
  out = %x{ruby #{Ebb::LIBDIR}/../bin/ebb_rails -v}
121
160
  assert_match %r{Ebb #{Ebb::VERSION}}, out
122
161
  end
162
+
163
+ # def get(path)
164
+ # Net::HTTP.get_response(URI.parse("http://0.0.0.0:4043#{path}"))
165
+ # end
166
+ #
167
+ # def test_starting_with_many_options
168
+ # %x{cd /tmp && rails ebb_test && ruby #{Ebb::LIBDIR}/../bin/ebb_rails start -d -e development -c /tmp/ebb_test -u www -g www -P /tmp/ebb.1.pid -p 4043 &}
169
+ # response = get('/')
170
+ # assert_equal 200, response.code
171
+ # ensure
172
+ # Process.kill('KILL', %x{cat /tmp/ebb.1.pid})
173
+ # end
123
174
  end
124
175
 
125
176
 
177
+
178
+
126
179
  #
127
180
  # class SocketTest < Test::Unit::TestCase
128
181
  # def test_socket_creation
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require File.dirname(__FILE__) + '/../ruby_lib/ebb'
4
+
5
+
6
+ class EchoApp
7
+ def call(env)
8
+ env['rack.input'] = env['rack.input'].read(1000000)
9
+ env.delete('rack.errors')
10
+ [200, {'Content-Type' => 'text/json'}, env.to_json]
11
+ end
12
+ end
13
+
14
+
15
+ server = Ebb::Server.new(EchoApp.new, :port => 4037)
16
+ server.start
@@ -0,0 +1,114 @@
1
+ require 'socket'
2
+ require 'rubygems'
3
+ require 'json'
4
+ require 'test/unit'
5
+
6
+ PORT = 4037
7
+
8
+ # This test depends on echo_server running at port 4037. I do this so that
9
+ # I can run a Python server at that port with a similar application and reuse
10
+ # these tests.
11
+
12
+ def send_request(request_string)
13
+ socket = TCPSocket.new("0.0.0.0", PORT)
14
+ socket.write(request_string)
15
+ lines = []
16
+ out = socket.read(5000000)
17
+ raise "Connection Closed on #{request_string.inspect}" if out.nil?
18
+ out.each_line { |l| lines << l }
19
+ env = JSON.parse(lines.last)
20
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE
21
+ return :fail
22
+ rescue RuntimeError => e
23
+ if e.message =~ /Connection Closed/
24
+ return :fail
25
+ else
26
+ raise e
27
+ end
28
+ rescue => e
29
+ puts "unknown exception: #{e.class}"
30
+ raise e
31
+ ensure
32
+ socket.close unless socket.nil?
33
+ end
34
+
35
+ def drops_request?(request_string)
36
+ :fail == send_request(request_string)
37
+ end
38
+
39
+ class HttpParserTest < Test::Unit::TestCase
40
+
41
+ def test_parse_simple
42
+ env = send_request("GET / HTTP/1.1\r\n\r\n")
43
+
44
+ assert_equal 'HTTP/1.1', env['SERVER_PROTOCOL']
45
+ assert_equal '/', env['REQUEST_PATH']
46
+ assert_equal 'HTTP/1.1', env['HTTP_VERSION']
47
+ assert_equal '/', env['REQUEST_URI']
48
+ assert_equal 'CGI/1.2', env['GATEWAY_INTERFACE']
49
+ assert_equal 'GET', env['REQUEST_METHOD']
50
+ assert_nil env['FRAGMENT']
51
+ assert_nil env['QUERY_STRING']
52
+ assert_nil env['rack.input']
53
+ end
54
+
55
+ def test_parse_dumbfuck_headers
56
+ should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
57
+ env = send_request(should_be_good)
58
+ assert_equal "++++++++++", env["HTTP_AAAAAAAAAAAAA"]
59
+ assert_nil env['rack.input']
60
+
61
+ nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n"
62
+ assert drops_request?(nasty_pound_header) # Correct?
63
+ end
64
+
65
+ def test_parse_error
66
+ assert drops_request?("GET / SsUTF/1.1")
67
+ end
68
+
69
+ def test_fragment_in_uri
70
+ env = send_request("GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n")
71
+ assert_equal '/forums/1/topics/2375?page=1', env['REQUEST_URI']
72
+ assert_equal 'posts-17408', env['FRAGMENT']
73
+ assert_nil env['rack.input']
74
+ end
75
+
76
+ # lame random garbage maker
77
+ def rand_data(min, max, readable=true)
78
+ count = min + ((rand(max)+1) *10).to_i
79
+ res = count.to_s + "/"
80
+
81
+ if readable
82
+ res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
83
+ else
84
+ res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
85
+ end
86
+
87
+ return res
88
+ end
89
+
90
+ def test_horrible_queries
91
+ 10.times do |c|
92
+ req = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
93
+ assert drops_request?(req), "large header names are caught"
94
+ end
95
+
96
+ # then that large mangled field values are caught
97
+ 10.times do |c|
98
+ req = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
99
+ assert drops_request?(req), "large mangled field values are caught"
100
+ ### XXX this is broken! fix me. this test should drop the request.
101
+ end
102
+
103
+ # then large headers are rejected too
104
+ req = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
105
+ req << "X-Test: test\r\n" * (80 * 1024)
106
+ assert drops_request?(req), "large headers are rejected"
107
+
108
+ # finally just that random garbage gets blocked all the time
109
+ 10.times do |c|
110
+ req = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
111
+ assert drops_request?(req), "random garbage gets blocked all the time"
112
+ end
113
+ end
114
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ebb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ry dahl
@@ -9,12 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-28 00:00:00 +01:00
12
+ date: 2008-03-03 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
16
  description: ""
17
- email: ry@tinyclouds.org
17
+ email: ry at tiny clouds dot org
18
18
  executables:
19
19
  - ebb_rails
20
20
  extensions:
@@ -22,13 +22,10 @@ extensions:
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
- - src/parser.rl
26
25
  - src/ebb.c
27
- - src/ebb_ruby.c
28
- - src/parser.c
29
26
  - src/ebb.h
27
+ - src/parser.c
30
28
  - src/parser.h
31
- - src/extconf.rb
32
29
  - libev/ev.c
33
30
  - libev/ev.h
34
31
  - libev/ev_epoll.c
@@ -39,6 +36,10 @@ files:
39
36
  - libev/ev_vars.h
40
37
  - libev/ev_win32.c
41
38
  - libev/ev_wrap.h
39
+ - VERSION
40
+ - README
41
+ - src/ebb_ruby.c
42
+ - src/extconf.rb
42
43
  - ruby_lib/daemonizable.rb
43
44
  - ruby_lib/ebb.rb
44
45
  - ruby_lib/rack
@@ -47,12 +48,12 @@ files:
47
48
  - benchmark/application.rb
48
49
  - benchmark/bench_results.rb
49
50
  - benchmark/server_test.rb
50
- - benchmark/test.rb
51
51
  - bin/ebb_rails
52
- - VERSION
53
- - README
52
+ - test/basic_test.rb
53
+ - test/echo_server.rb
54
+ - test/env_test.rb
54
55
  has_rdoc: false
55
- homepage: http://repo.or.cz/w/ebb.git
56
+ homepage: http://ebb.rubyforge.org
56
57
  post_install_message:
57
58
  rdoc_options: []
58
59
 
@@ -1,200 +0,0 @@
1
- /**
2
- * Copyright (c) 2005 Zed A. Shaw
3
- * You can redistribute it and/or modify it under the same terms as Ruby.
4
- */
5
- #include "parser.h"
6
- #include <stdio.h>
7
- #include <assert.h>
8
- #include <stdlib.h>
9
- #include <ctype.h>
10
- #include <string.h>
11
-
12
- #define LEN(AT, FPC) (FPC - buffer - parser->AT)
13
- #define MARK(M,FPC) (parser->M = (FPC) - buffer)
14
- #define PTR_TO(F) (buffer + parser->F)
15
-
16
- /** machine **/
17
- %%{
18
- machine http_parser;
19
-
20
- action mark {MARK(mark, fpc); }
21
-
22
-
23
- action start_field { MARK(field_start, fpc); }
24
- action write_field {
25
- parser->field_len = LEN(field_start, fpc);
26
- }
27
-
28
- action start_value { MARK(mark, fpc); }
29
- action write_value {
30
- if(parser->http_field != NULL) {
31
- parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
32
- }
33
- }
34
-
35
- action content_length {
36
- if(parser->content_length != NULL) {
37
- parser->content_length(parser->data, PTR_TO(mark), LEN(mark, fpc));
38
- }
39
- }
40
-
41
- action request_method {
42
- if(parser->request_method != NULL)
43
- parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
44
- }
45
- action request_uri {
46
- if(parser->request_uri != NULL)
47
- parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
48
- }
49
-
50
- action start_query {MARK(query_start, fpc); }
51
- action query_string {
52
- if(parser->query_string != NULL)
53
- parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
54
- }
55
-
56
- action http_version {
57
- if(parser->http_version != NULL)
58
- parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
59
- }
60
-
61
- action request_path {
62
- if(parser->request_path != NULL)
63
- parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
64
- }
65
-
66
- action done {
67
- parser->body_start = fpc - buffer + 1;
68
- if(parser->header_done != NULL)
69
- parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
70
- fbreak;
71
- }
72
-
73
-
74
- #### HTTP PROTOCOL GRAMMAR
75
- # line endings
76
- CRLF = "\r\n";
77
-
78
- # character types
79
- CTL = (cntrl | 127);
80
- safe = ("$" | "-" | "_" | ".");
81
- extra = ("!" | "*" | "'" | "(" | ")" | ",");
82
- reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
83
- unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">");
84
- national = any -- (alpha | digit | reserved | extra | safe | unsafe);
85
- unreserved = (alpha | digit | safe | extra | national);
86
- escape = ("%" xdigit xdigit);
87
- uchar = (unreserved | escape);
88
- pchar = (uchar | ":" | "@" | "&" | "=" | "+");
89
- tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
90
-
91
- # elements
92
- token = (ascii -- (CTL | tspecials));
93
-
94
- # URI schemes and absolute paths
95
- scheme = ( alpha | digit | "+" | "-" | "." )* ;
96
- absolute_uri = (scheme ":" (uchar | reserved )*);
97
-
98
- path = (pchar+ ( "/" pchar* )*) ;
99
- query = ( uchar | reserved )* %query_string ;
100
- param = ( pchar | "/" )* ;
101
- params = (param ( ";" param )*) ;
102
- rel_path = (path? %request_path (";" params)?) ("?" %start_query query)?;
103
- absolute_path = ("/"+ rel_path);
104
-
105
- Request_URI = ("*" | absolute_uri | absolute_path) >mark %request_uri;
106
- Method = (upper | digit | safe){1,20} >mark %request_method;
107
-
108
- http_number = (digit+ "." digit+) ;
109
- HTTP_Version = ("HTTP/" http_number) >mark %http_version ;
110
- Request_Line = (Method " " Request_URI " " HTTP_Version CRLF) ;
111
-
112
- field_name = (token -- ":")+ >start_field %write_field;
113
-
114
- field_value = any* >start_value %write_value;
115
-
116
- message_header = field_name ":" " "* field_value :> CRLF;
117
- content_length = "Content-Length:"i " "* (field_value >mark %content_length) :> CRLF;
118
-
119
- Request = Request_Line (content_length | message_header)* ( CRLF @done);
120
-
121
- main := Request;
122
- }%%
123
-
124
- /** Data **/
125
- %% write data;
126
-
127
- int http_parser_init(http_parser *parser) {
128
- int cs = 0;
129
- %% write init;
130
- parser->cs = cs;
131
- parser->body_start = 0;
132
- parser->content_len = 0;
133
- parser->mark = 0;
134
- parser->nread = 0;
135
- parser->field_len = 0;
136
- parser->field_start = 0;
137
-
138
- return(1);
139
- }
140
-
141
-
142
- /** exec **/
143
- size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
144
- const char *p, *pe;
145
- int cs = parser->cs;
146
-
147
- assert(off <= len && "offset past end of buffer");
148
-
149
- p = buffer+off;
150
- pe = buffer+len;
151
-
152
- assert(*pe == '\0' && "pointer does not end on NUL");
153
- assert(pe - p == len - off && "pointers aren't same distance");
154
-
155
-
156
- %% write exec;
157
-
158
- parser->cs = cs;
159
- parser->nread += p - (buffer + off);
160
-
161
- assert(p <= pe && "buffer overflow after parsing execute");
162
- assert(parser->nread <= len && "nread longer than length");
163
- assert(parser->body_start <= len && "body starts after buffer end");
164
- assert(parser->mark < len && "mark is after buffer end");
165
- assert(parser->field_len <= len && "field has length longer than whole buffer");
166
- assert(parser->field_start < len && "field starts after buffer end");
167
-
168
- if(parser->body_start) {
169
- /* final \r\n combo encountered so stop right here */
170
- %%write eof;
171
- parser->nread++;
172
- }
173
-
174
- return(parser->nread);
175
- }
176
-
177
- int http_parser_finish(http_parser *parser)
178
- {
179
- int cs = parser->cs;
180
-
181
- %%write eof;
182
-
183
- parser->cs = cs;
184
-
185
- if (http_parser_has_error(parser) ) {
186
- return -1;
187
- } else if (http_parser_is_finished(parser) ) {
188
- return 1;
189
- } else {
190
- return 0;
191
- }
192
- }
193
-
194
- int http_parser_has_error(http_parser *parser) {
195
- return parser->cs == http_parser_error;
196
- }
197
-
198
- int http_parser_is_finished(http_parser *parser) {
199
- return parser->cs == http_parser_first_final;
200
- }