ebb 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- }