Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial files

  • Loading branch information...
commit 18bbafe9a05968459badac55f0f58c40f9ded49a 0 parents
Lakshan authored
38 headers.rb
@@ -0,0 +1,38 @@
+ # Store HTTP header name-value pairs direcly to a string
+ # and allow duplicated entries on some names.
+ class Headers
+ HEADER_FORMAT = "%s: %s\r\n".freeze
+ ALLOWED_DUPLICATES = %w(Set-Cookie Set-Cookie2 Warning WWW-Authenticate).freeze
+
+ def initialize
+ @sent = {}
+ @out = []
+ end
+
+ # Add <tt>key: value</tt> pair to the headers.
+ # Ignore if already sent and no duplicates are allowed
+ # for this +key+.
+ def []=(key, value)
+ if !@sent.has_key?(key) || ALLOWED_DUPLICATES.include?(key)
+ @sent[key] = true
+ value = case value
+ when Time
+ value.httpdate
+ when NilClass
+ return
+ else
+ value.to_s
+ end
+ @out << HEADER_FORMAT % [key, value]
+ end
+ end
+
+ def has_key?(key)
+ @sent[key]
+ end
+
+ def to_s
+ @out.join
+ end
+ end
+
105 request.rb
@@ -0,0 +1,105 @@
+require "thin_parser"
+require "stringio"
+
+class InvalidRequest < IOError; end
+
+ # A request sent by the client to the server.
+class Request
+ # Maximum request body size before it is moved out of memory
+ # and into a tempfile for reading.
+ MAX_BODY = 1024 * (80 + 32)
+ BODY_TMPFILE = 'thin-body'.freeze
+ MAX_HEADER = 1024 * (80 + 32)
+
+ INITIAL_BODY = ''
+ # Force external_encoding of request's body to ASCII_8BIT
+ INITIAL_BODY.encode!(Encoding::ASCII_8BIT) if INITIAL_BODY.respond_to?(:encode)
+
+ # Freeze some HTTP header names & values
+ SERVER_SOFTWARE = 'SERVER_SOFTWARE'.freeze
+ SERVER_NAME = 'SERVER_NAME'.freeze
+ LOCALHOST = 'localhost'.freeze
+ HTTP_VERSION = 'HTTP_VERSION'.freeze
+ HTTP_1_0 = 'HTTP/1.0'.freeze
+ REMOTE_ADDR = 'REMOTE_ADDR'.freeze
+ CONTENT_LENGTH = 'CONTENT_LENGTH'.freeze
+ CONNECTION = 'HTTP_CONNECTION'.freeze
+ KEEP_ALIVE_REGEXP = /\bkeep-alive\b/i.freeze
+ CLOSE_REGEXP = /\bclose\b/i.freeze
+
+ # Freeze some Rack header names
+ RACK_INPUT = 'rack.input'.freeze
+ RACK_VERSION = 'rack.version'.freeze
+ RACK_ERRORS = 'rack.errors'.freeze
+ RACK_MULTITHREAD = 'rack.multithread'.freeze
+ RACK_MULTIPROCESS = 'rack.multiprocess'.freeze
+ RACK_RUN_ONCE = 'rack.run_once'.freeze
+ ASYNC_CALLBACK = 'async.callback'.freeze
+ ASYNC_CLOSE = 'async.close'.freeze
+
+ # CGI-like request environment variables
+ attr_reader :env
+
+ # Unparsed data of the request
+ attr_reader :data
+
+ # Request body
+ # attr_reader :body
+ attr_accessor :messages
+
+ def initialize
+ @parser = Thin::HttpParser.new
+ @data = ''
+ @nparsed = 0
+ @messages = "" #StringIO.new(INITIAL_BODY.dup)
+ @env = {
+ SERVER_SOFTWARE => "WebSocketThin",
+ SERVER_NAME => LOCALHOST,
+
+ # Rack stuff
+ RACK_INPUT => @messages,
+
+ RACK_VERSION => [1, 0].freeze, #VERSION::RACK,
+ RACK_ERRORS => STDERR,
+
+ RACK_MULTITHREAD => false,
+ RACK_MULTIPROCESS => false,
+ RACK_RUN_ONCE => false
+ }
+ end
+
+ # Parse a chunk of data into the request environment
+ # Raises a +InvalidRequest+ if invalid.
+ # Returns +true+ if the parsing is complete.
+ def parse(data)
+ if @parser.finished? # Header finished, can only be some more body
+ @messages << data
+ else # Parse more header using the super parser
+ @data << data
+ raise InvalidRequest, 'Header longer than allowed' if @data.size > MAX_HEADER
+
+ @nparsed = @parser.execute(@env, @data, @nparsed)
+
+ # Transfert to a tempfile if body is very big
+ # move_body_to_tempfile if @parser.finished? && content_length > MAX_BODY
+ end
+
+ if finished? # Check if header and body are complete
+ @data = nil
+ #@body.rewind
+ true # Request is fully parsed
+ else
+ false # Not finished, need more data
+ end
+ end
+
+ # +true+ if headers and body are finished parsing
+ def finished?
+ @parser.finished? && @messages.size >= content_length
+ end
+
+ # Expected size of the body
+ def content_length
+ @env[CONTENT_LENGTH].to_i
+ end
+end
157 thin_parser/Makefile
@@ -0,0 +1,157 @@
+
+SHELL = /bin/sh
+
+#### Start of system configuration section. ####
+
+srcdir = .
+topdir = /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin10.0
+hdrdir = $(topdir)
+VPATH = $(srcdir):$(topdir):$(hdrdir)
+exec_prefix = $(prefix)
+prefix = $(DESTDIR)/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr
+sharedstatedir = $(prefix)/com
+mandir = $(DESTDIR)/usr/share/man
+psdir = $(docdir)
+oldincludedir = $(DESTDIR)/usr/include
+localedir = $(datarootdir)/locale
+bindir = $(exec_prefix)/bin
+libexecdir = $(exec_prefix)/libexec
+sitedir = $(DESTDIR)/Library/Ruby/Site
+htmldir = $(docdir)
+vendorarchdir = $(vendorlibdir)/$(sitearch)
+includedir = $(prefix)/include
+infodir = $(DESTDIR)/usr/share/info
+vendorlibdir = $(vendordir)/$(ruby_version)
+sysconfdir = $(prefix)/etc
+libdir = $(exec_prefix)/lib
+sbindir = $(exec_prefix)/sbin
+rubylibdir = $(libdir)/ruby/$(ruby_version)
+docdir = $(datarootdir)/doc/$(PACKAGE)
+dvidir = $(docdir)
+vendordir = $(libdir)/ruby/vendor_ruby
+datarootdir = $(prefix)/share
+pdfdir = $(docdir)
+archdir = $(rubylibdir)/$(arch)
+sitearchdir = $(sitelibdir)/$(sitearch)
+datadir = $(datarootdir)
+localstatedir = $(prefix)/var
+sitelibdir = $(sitedir)/$(ruby_version)
+
+CC = gcc
+LIBRUBY = $(LIBRUBY_SO)
+LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
+LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
+LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)
+
+RUBY_EXTCONF_H =
+CFLAGS = -fno-common -arch i386 -arch x86_64 -g -Os -pipe -fno-common -DENABLE_DTRACE -fno-common -pipe -fno-common $(cflags)
+INCFLAGS = -I. -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin10.0 -I.
+DEFS =
+CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE
+CXXFLAGS = $(CFLAGS)
+ldflags = -L. -arch i386 -arch x86_64
+dldflags =
+archflag =
+DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
+LDSHARED = cc -arch i386 -arch x86_64 -pipe -bundle -undefined dynamic_lookup
+AR = ar
+EXEEXT =
+
+RUBY_INSTALL_NAME = ruby
+RUBY_SO_NAME = ruby
+arch = universal-darwin10.0
+sitearch = universal-darwin10.0
+ruby_version = 1.8
+ruby = /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
+RUBY = $(ruby)
+RM = rm -f
+MAKEDIRS = mkdir -p
+INSTALL = /usr/bin/install -c
+INSTALL_PROG = $(INSTALL) -m 0755
+INSTALL_DATA = $(INSTALL) -m 644
+COPY = cp
+
+#### End of system configuration section. ####
+
+preload =
+
+libpath = . $(libdir)
+LIBPATH = -L. -L$(libdir)
+DEFFILE =
+
+CLEANFILES = mkmf.log
+DISTCLEANFILES =
+
+extout =
+extout_prefix =
+target_prefix =
+LOCAL_LIBS =
+LIBS = $(LIBRUBYARG_SHARED) -lc -lpthread -ldl
+SRCS = parser.c thin.c
+OBJS = parser.o thin.o
+TARGET = thin_parser
+DLLIB = $(TARGET).bundle
+EXTSTATIC =
+STATIC_LIB =
+
+BINDIR = $(bindir)
+RUBYCOMMONDIR = $(sitedir)$(target_prefix)
+RUBYLIBDIR = $(sitelibdir)$(target_prefix)
+RUBYARCHDIR = $(sitearchdir)$(target_prefix)
+
+TARGET_SO = $(DLLIB)
+CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
+CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
+
+all: $(DLLIB)
+static: $(STATIC_LIB)
+
+clean:
+ @-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
+
+distclean: clean
+ @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
+ @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
+
+realclean: distclean
+install: install-so install-rb
+
+install-so: $(RUBYARCHDIR)
+install-so: $(RUBYARCHDIR)/$(DLLIB)
+$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
+install-rb: pre-install-rb install-rb-default
+install-rb-default: pre-install-rb-default
+pre-install-rb: Makefile
+pre-install-rb-default: Makefile
+$(RUBYARCHDIR):
+ $(MAKEDIRS) $@
+
+site-install: site-install-so site-install-rb
+site-install-so: install-so
+site-install-rb: install-rb
+
+.SUFFIXES: .c .m .cc .cxx .cpp .C .o
+
+.cc.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.cxx.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.cpp.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.C.o:
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
+
+.c.o:
+ $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
+
+$(DLLIB): $(OBJS)
+ @-$(RM) $@
+ $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
+
+
+
+$(OBJS): ruby.h defines.h
55 thin_parser/common.rl
@@ -0,0 +1,55 @@
+%%{
+
+ machine http_parser_common;
+
+#### HTTP PROTOCOL GRAMMAR
+# line endings
+ CRLF = "\r\n";
+
+# character types
+ CTL = (cntrl | 127);
+ safe = ("$" | "-" | "_" | ".");
+ extra = ("!" | "*" | "'" | "(" | ")" | ",");
+ reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
+ sorta_safe = ("\"" | "<" | ">");
+ unsafe = (CTL | " " | "#" | "%" | sorta_safe);
+ national = any -- (alpha | digit | reserved | extra | safe | unsafe);
+ unreserved = (alpha | digit | safe | extra | national);
+ escape = ("%" xdigit xdigit);
+ uchar = (unreserved | escape | sorta_safe);
+ pchar = (uchar | ":" | "@" | "&" | "=" | "+");
+ tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
+
+# elements
+ token = (ascii -- (CTL | tspecials));
+
+# URI schemes and absolute paths
+ scheme = ( alpha | digit | "+" | "-" | "." )* ;
+ absolute_uri = (scheme ":" (uchar | reserved )*);
+
+ path = ( pchar+ ( "/" pchar* )* ) ;
+ query = ( uchar | reserved )* %query_string ;
+ param = ( pchar | "/" )* ;
+ params = ( param ( ";" param )* ) ;
+ rel_path = ( path? (";" params)? %request_path) ("?" %start_query query)?;
+ absolute_path = ( "/"+ rel_path );
+
+ Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
+ Fragment = ( uchar | reserved )* >mark %fragment;
+ Method = ( upper | digit | safe ){1,20} >mark %request_method;
+
+ http_number = ( digit+ "." digit+ ) ;
+ HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
+ Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
+
+ field_name = ( token -- ":" )+ >start_field %write_field;
+
+ field_value = any* >start_value %write_value;
+
+ message_header = field_name ":" " "* field_value :> CRLF;
+
+ Request = Request_Line ( message_header )* ( CRLF @done );
+
+main := Request;
+
+}%%
14 thin_parser/ext_help.h
@@ -0,0 +1,14 @@
+#ifndef ext_help_h
+#define ext_help_h
+
+#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
+#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
+#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
+
+#ifdef DEBUG
+#define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
+#else
+#define TRACE()
+#endif
+
+#endif
6 thin_parser/extconf.rb
@@ -0,0 +1,6 @@
+require 'mkmf'
+
+dir_config("thin_parser")
+have_library("c", "main")
+
+create_makefile("thin_parser")
12 thin_parser/mkmf.log
@@ -0,0 +1,12 @@
+have_library: checking for main() in -lc... -------------------- yes
+
+"gcc -o conftest -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin10.0 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -arch i386 -arch x86_64 -g -Os -pipe -fno-common -DENABLE_DTRACE -fno-common -pipe -fno-common conftest.c -L. -L/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib -L. -arch i386 -arch x86_64 -lruby -lc -lpthread -ldl "
+checked program was:
+/* begin */
+1: /*top*/
+2: int main() { return 0; }
+3: int t() { void ((*volatile p)()); p = (void ((*)()))main; return 0; }
+/* end */
+
+--------------------
+
1,185 thin_parser/parser.c
@@ -0,0 +1,1185 @@
+
+#line 1 "parser.rl"
+/**
+ * Copyright (c) 2005 Zed A. Shaw
+ * You can redistribute it and/or modify it under the same terms as Ruby.
+ */
+#include "parser.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define LEN(AT, FPC) (FPC - buffer - parser->AT)
+#define MARK(M,FPC) (parser->M = (FPC) - buffer)
+#define PTR_TO(F) (buffer + parser->F)
+
+/** Machine **/
+
+
+#line 81 "parser.rl"
+
+
+/** Data **/
+
+#line 27 "parser.c"
+static const int http_parser_start = 1;
+static const int http_parser_first_final = 54;
+static const int http_parser_error = 0;
+
+static const int http_parser_en_main = 1;
+
+
+#line 85 "parser.rl"
+
+int thin_http_parser_init(http_parser *parser) {
+ int cs = 0;
+
+#line 40 "parser.c"
+ {
+ cs = http_parser_start;
+ }
+
+#line 89 "parser.rl"
+ parser->cs = cs;
+ parser->body_start = 0;
+ parser->content_len = 0;
+ parser->mark = 0;
+ parser->nread = 0;
+ parser->field_len = 0;
+ parser->field_start = 0;
+
+ return(1);
+}
+
+
+/** exec **/
+size_t thin_http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
+ const char *p, *pe;
+ int cs = parser->cs;
+
+ assert(off <= len && "offset past end of buffer");
+
+ p = buffer+off;
+ pe = buffer+len;
+
+ assert(*pe == '\0' && "pointer does not end on NUL");
+ assert(pe - p == len - off && "pointers aren't same distance");
+
+
+
+#line 73 "parser.c"
+ {
+ if ( p == pe )
+ goto _test_eof;
+ switch ( cs )
+ {
+case 1:
+ switch( (*p) ) {
+ case 36: goto tr0;
+ case 95: goto tr0;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto tr0;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto tr0;
+ } else
+ goto tr0;
+ goto st0;
+st0:
+cs = 0;
+ goto _out;
+tr0:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st2;
+st2:
+ if ( ++p == pe )
+ goto _test_eof2;
+case 2:
+#line 104 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st35;
+ case 95: goto st35;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st35;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st35;
+ } else
+ goto st35;
+ goto st0;
+tr2:
+#line 36 "parser.rl"
+ {
+ if (parser->request_method != NULL) {
+ parser->request_method(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st3;
+st3:
+ if ( ++p == pe )
+ goto _test_eof3;
+case 3:
+#line 131 "parser.c"
+ switch( (*p) ) {
+ case 42: goto tr4;
+ case 43: goto tr5;
+ case 47: goto tr6;
+ case 58: goto tr7;
+ }
+ if ( (*p) < 65 ) {
+ if ( 45 <= (*p) && (*p) <= 57 )
+ goto tr5;
+ } else if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto tr5;
+ } else
+ goto tr5;
+ goto st0;
+tr4:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st4;
+st4:
+ if ( ++p == pe )
+ goto _test_eof4;
+case 4:
+#line 155 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr8;
+ case 35: goto tr9;
+ }
+ goto st0;
+tr8:
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st5;
+tr31:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+#line 46 "parser.rl"
+ {
+ if (parser->fragment != NULL) {
+ parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st5;
+tr34:
+#line 46 "parser.rl"
+ {
+ if (parser->fragment != NULL) {
+ parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st5;
+tr42:
+#line 65 "parser.rl"
+ {
+ if (parser->request_path != NULL) {
+ parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+ }
+ }
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st5;
+tr48:
+#line 52 "parser.rl"
+ {MARK(query_start, p); }
+#line 53 "parser.rl"
+ {
+ if (parser->query_string != NULL) {
+ parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+ }
+ }
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st5;
+tr52:
+#line 53 "parser.rl"
+ {
+ if (parser->query_string != NULL) {
+ parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+ }
+ }
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st5;
+st5:
+ if ( ++p == pe )
+ goto _test_eof5;
+case 5:
+#line 235 "parser.c"
+ if ( (*p) == 72 )
+ goto tr10;
+ goto st0;
+tr10:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st6;
+st6:
+ if ( ++p == pe )
+ goto _test_eof6;
+case 6:
+#line 247 "parser.c"
+ if ( (*p) == 84 )
+ goto st7;
+ goto st0;
+st7:
+ if ( ++p == pe )
+ goto _test_eof7;
+case 7:
+ if ( (*p) == 84 )
+ goto st8;
+ goto st0;
+st8:
+ if ( ++p == pe )
+ goto _test_eof8;
+case 8:
+ if ( (*p) == 80 )
+ goto st9;
+ goto st0;
+st9:
+ if ( ++p == pe )
+ goto _test_eof9;
+case 9:
+ if ( (*p) == 47 )
+ goto st10;
+ goto st0;
+st10:
+ if ( ++p == pe )
+ goto _test_eof10;
+case 10:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st11;
+ goto st0;
+st11:
+ if ( ++p == pe )
+ goto _test_eof11;
+case 11:
+ if ( (*p) == 46 )
+ goto st12;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st11;
+ goto st0;
+st12:
+ if ( ++p == pe )
+ goto _test_eof12;
+case 12:
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st13;
+ goto st0;
+st13:
+ if ( ++p == pe )
+ goto _test_eof13;
+case 13:
+ if ( (*p) == 13 )
+ goto tr18;
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st13;
+ goto st0;
+tr18:
+#line 59 "parser.rl"
+ {
+ if (parser->http_version != NULL) {
+ parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st14;
+tr26:
+#line 30 "parser.rl"
+ { MARK(mark, p); }
+#line 31 "parser.rl"
+ {
+ if (parser->http_field != NULL) {
+ parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st14;
+tr29:
+#line 31 "parser.rl"
+ {
+ if (parser->http_field != NULL) {
+ parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st14;
+st14:
+ if ( ++p == pe )
+ goto _test_eof14;
+case 14:
+#line 334 "parser.c"
+ if ( (*p) == 10 )
+ goto st15;
+ goto st0;
+st15:
+ if ( ++p == pe )
+ goto _test_eof15;
+case 15:
+ switch( (*p) ) {
+ case 13: goto st16;
+ case 33: goto tr21;
+ case 124: goto tr21;
+ case 126: goto tr21;
+ }
+ if ( (*p) < 45 ) {
+ if ( (*p) > 39 ) {
+ if ( 42 <= (*p) && (*p) <= 43 )
+ goto tr21;
+ } else if ( (*p) >= 35 )
+ goto tr21;
+ } else if ( (*p) > 46 ) {
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto tr21;
+ } else if ( (*p) > 90 ) {
+ if ( 94 <= (*p) && (*p) <= 122 )
+ goto tr21;
+ } else
+ goto tr21;
+ } else
+ goto tr21;
+ goto st0;
+st16:
+ if ( ++p == pe )
+ goto _test_eof16;
+case 16:
+ if ( (*p) == 10 )
+ goto tr22;
+ goto st0;
+tr22:
+#line 71 "parser.rl"
+ {
+ parser->body_start = p - buffer + 1;
+ if (parser->header_done != NULL) {
+ parser->header_done(parser->data, p + 1, pe - p - 1);
+ }
+ {p++; cs = 54; goto _out;}
+ }
+ goto st54;
+st54:
+ if ( ++p == pe )
+ goto _test_eof54;
+case 54:
+#line 387 "parser.c"
+ goto st0;
+tr21:
+#line 25 "parser.rl"
+ { MARK(field_start, p); }
+ goto st17;
+st17:
+ if ( ++p == pe )
+ goto _test_eof17;
+case 17:
+#line 397 "parser.c"
+ switch( (*p) ) {
+ case 33: goto st17;
+ case 58: goto tr24;
+ case 124: goto st17;
+ case 126: goto st17;
+ }
+ if ( (*p) < 45 ) {
+ if ( (*p) > 39 ) {
+ if ( 42 <= (*p) && (*p) <= 43 )
+ goto st17;
+ } else if ( (*p) >= 35 )
+ goto st17;
+ } else if ( (*p) > 46 ) {
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st17;
+ } else if ( (*p) > 90 ) {
+ if ( 94 <= (*p) && (*p) <= 122 )
+ goto st17;
+ } else
+ goto st17;
+ } else
+ goto st17;
+ goto st0;
+tr24:
+#line 26 "parser.rl"
+ {
+ parser->field_len = LEN(field_start, p);
+ }
+ goto st18;
+tr27:
+#line 30 "parser.rl"
+ { MARK(mark, p); }
+ goto st18;
+st18:
+ if ( ++p == pe )
+ goto _test_eof18;
+case 18:
+#line 436 "parser.c"
+ switch( (*p) ) {
+ case 13: goto tr26;
+ case 32: goto tr27;
+ }
+ goto tr25;
+tr25:
+#line 30 "parser.rl"
+ { MARK(mark, p); }
+ goto st19;
+st19:
+ if ( ++p == pe )
+ goto _test_eof19;
+case 19:
+#line 450 "parser.c"
+ if ( (*p) == 13 )
+ goto tr29;
+ goto st19;
+tr9:
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st20;
+tr43:
+#line 65 "parser.rl"
+ {
+ if (parser->request_path != NULL) {
+ parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+ }
+ }
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st20;
+tr49:
+#line 52 "parser.rl"
+ {MARK(query_start, p); }
+#line 53 "parser.rl"
+ {
+ if (parser->query_string != NULL) {
+ parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+ }
+ }
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st20;
+tr53:
+#line 53 "parser.rl"
+ {
+ if (parser->query_string != NULL) {
+ parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+ }
+ }
+#line 41 "parser.rl"
+ {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+ }
+ }
+ goto st20;
+st20:
+ if ( ++p == pe )
+ goto _test_eof20;
+case 20:
+#line 510 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr31;
+ case 35: goto st0;
+ case 37: goto tr32;
+ case 127: goto st0;
+ }
+ if ( 0 <= (*p) && (*p) <= 31 )
+ goto st0;
+ goto tr30;
+tr30:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st21;
+st21:
+ if ( ++p == pe )
+ goto _test_eof21;
+case 21:
+#line 528 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr34;
+ case 35: goto st0;
+ case 37: goto st22;
+ case 127: goto st0;
+ }
+ if ( 0 <= (*p) && (*p) <= 31 )
+ goto st0;
+ goto st21;
+tr32:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st22;
+st22:
+ if ( ++p == pe )
+ goto _test_eof22;
+case 22:
+#line 546 "parser.c"
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st23;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st23;
+ } else
+ goto st23;
+ goto st0;
+st23:
+ if ( ++p == pe )
+ goto _test_eof23;
+case 23:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st21;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st21;
+ } else
+ goto st21;
+ goto st0;
+tr5:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st24;
+st24:
+ if ( ++p == pe )
+ goto _test_eof24;
+case 24:
+#line 577 "parser.c"
+ switch( (*p) ) {
+ case 43: goto st24;
+ case 58: goto st25;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st24;
+ } else if ( (*p) > 57 ) {
+ if ( (*p) > 90 ) {
+ if ( 97 <= (*p) && (*p) <= 122 )
+ goto st24;
+ } else if ( (*p) >= 65 )
+ goto st24;
+ } else
+ goto st24;
+ goto st0;
+tr7:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st25;
+st25:
+ if ( ++p == pe )
+ goto _test_eof25;
+case 25:
+#line 602 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr8;
+ case 35: goto tr9;
+ case 37: goto st26;
+ case 127: goto st0;
+ }
+ if ( 0 <= (*p) && (*p) <= 31 )
+ goto st0;
+ goto st25;
+st26:
+ if ( ++p == pe )
+ goto _test_eof26;
+case 26:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st27;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st27;
+ } else
+ goto st27;
+ goto st0;
+st27:
+ if ( ++p == pe )
+ goto _test_eof27;
+case 27:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st25;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st25;
+ } else
+ goto st25;
+ goto st0;
+tr6:
+#line 22 "parser.rl"
+ {MARK(mark, p); }
+ goto st28;
+st28:
+ if ( ++p == pe )
+ goto _test_eof28;
+case 28:
+#line 646 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr42;
+ case 35: goto tr43;
+ case 37: goto st29;
+ case 63: goto tr45;
+ case 127: goto st0;
+ }
+ if ( 0 <= (*p) && (*p) <= 31 )
+ goto st0;
+ goto st28;
+st29:
+ if ( ++p == pe )
+ goto _test_eof29;
+case 29:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st30;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st30;
+ } else
+ goto st30;
+ goto st0;
+st30:
+ if ( ++p == pe )
+ goto _test_eof30;
+case 30:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st28;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st28;
+ } else
+ goto st28;
+ goto st0;
+tr45:
+#line 65 "parser.rl"
+ {
+ if (parser->request_path != NULL) {
+ parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+ }
+ }
+ goto st31;
+st31:
+ if ( ++p == pe )
+ goto _test_eof31;
+case 31:
+#line 695 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr48;
+ case 35: goto tr49;
+ case 37: goto tr50;
+ case 127: goto st0;
+ }
+ if ( 0 <= (*p) && (*p) <= 31 )
+ goto st0;
+ goto tr47;
+tr47:
+#line 52 "parser.rl"
+ {MARK(query_start, p); }
+ goto st32;
+st32:
+ if ( ++p == pe )
+ goto _test_eof32;
+case 32:
+#line 713 "parser.c"
+ switch( (*p) ) {
+ case 32: goto tr52;
+ case 35: goto tr53;
+ case 37: goto st33;
+ case 127: goto st0;
+ }
+ if ( 0 <= (*p) && (*p) <= 31 )
+ goto st0;
+ goto st32;
+tr50:
+#line 52 "parser.rl"
+ {MARK(query_start, p); }
+ goto st33;
+st33:
+ if ( ++p == pe )
+ goto _test_eof33;
+case 33:
+#line 731 "parser.c"
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st34;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st34;
+ } else
+ goto st34;
+ goto st0;
+st34:
+ if ( ++p == pe )
+ goto _test_eof34;
+case 34:
+ if ( (*p) < 65 ) {
+ if ( 48 <= (*p) && (*p) <= 57 )
+ goto st32;
+ } else if ( (*p) > 70 ) {
+ if ( 97 <= (*p) && (*p) <= 102 )
+ goto st32;
+ } else
+ goto st32;
+ goto st0;
+st35:
+ if ( ++p == pe )
+ goto _test_eof35;
+case 35:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st36;
+ case 95: goto st36;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st36;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st36;
+ } else
+ goto st36;
+ goto st0;
+st36:
+ if ( ++p == pe )
+ goto _test_eof36;
+case 36:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st37;
+ case 95: goto st37;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st37;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st37;
+ } else
+ goto st37;
+ goto st0;
+st37:
+ if ( ++p == pe )
+ goto _test_eof37;
+case 37:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st38;
+ case 95: goto st38;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st38;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st38;
+ } else
+ goto st38;
+ goto st0;
+st38:
+ if ( ++p == pe )
+ goto _test_eof38;
+case 38:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st39;
+ case 95: goto st39;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st39;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st39;
+ } else
+ goto st39;
+ goto st0;
+st39:
+ if ( ++p == pe )
+ goto _test_eof39;
+case 39:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st40;
+ case 95: goto st40;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st40;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st40;
+ } else
+ goto st40;
+ goto st0;
+st40:
+ if ( ++p == pe )
+ goto _test_eof40;
+case 40:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st41;
+ case 95: goto st41;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st41;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st41;
+ } else
+ goto st41;
+ goto st0;
+st41:
+ if ( ++p == pe )
+ goto _test_eof41;
+case 41:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st42;
+ case 95: goto st42;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st42;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st42;
+ } else
+ goto st42;
+ goto st0;
+st42:
+ if ( ++p == pe )
+ goto _test_eof42;
+case 42:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st43;
+ case 95: goto st43;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st43;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st43;
+ } else
+ goto st43;
+ goto st0;
+st43:
+ if ( ++p == pe )
+ goto _test_eof43;
+case 43:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st44;
+ case 95: goto st44;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st44;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st44;
+ } else
+ goto st44;
+ goto st0;
+st44:
+ if ( ++p == pe )
+ goto _test_eof44;
+case 44:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st45;
+ case 95: goto st45;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st45;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st45;
+ } else
+ goto st45;
+ goto st0;
+st45:
+ if ( ++p == pe )
+ goto _test_eof45;
+case 45:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st46;
+ case 95: goto st46;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st46;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st46;
+ } else
+ goto st46;
+ goto st0;
+st46:
+ if ( ++p == pe )
+ goto _test_eof46;
+case 46:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st47;
+ case 95: goto st47;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st47;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st47;
+ } else
+ goto st47;
+ goto st0;
+st47:
+ if ( ++p == pe )
+ goto _test_eof47;
+case 47:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st48;
+ case 95: goto st48;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st48;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st48;
+ } else
+ goto st48;
+ goto st0;
+st48:
+ if ( ++p == pe )
+ goto _test_eof48;
+case 48:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st49;
+ case 95: goto st49;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st49;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st49;
+ } else
+ goto st49;
+ goto st0;
+st49:
+ if ( ++p == pe )
+ goto _test_eof49;
+case 49:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st50;
+ case 95: goto st50;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st50;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st50;
+ } else
+ goto st50;
+ goto st0;
+st50:
+ if ( ++p == pe )
+ goto _test_eof50;
+case 50:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st51;
+ case 95: goto st51;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st51;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st51;
+ } else
+ goto st51;
+ goto st0;
+st51:
+ if ( ++p == pe )
+ goto _test_eof51;
+case 51:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st52;
+ case 95: goto st52;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st52;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st52;
+ } else
+ goto st52;
+ goto st0;
+st52:
+ if ( ++p == pe )
+ goto _test_eof52;
+case 52:
+ switch( (*p) ) {
+ case 32: goto tr2;
+ case 36: goto st53;
+ case 95: goto st53;
+ }
+ if ( (*p) < 48 ) {
+ if ( 45 <= (*p) && (*p) <= 46 )
+ goto st53;
+ } else if ( (*p) > 57 ) {
+ if ( 65 <= (*p) && (*p) <= 90 )
+ goto st53;
+ } else
+ goto st53;
+ goto st0;
+st53:
+ if ( ++p == pe )
+ goto _test_eof53;
+case 53:
+ if ( (*p) == 32 )
+ goto tr2;
+ goto st0;
+ }
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof54: cs = 54; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof30: cs = 30; goto _test_eof;
+ _test_eof31: cs = 31; goto _test_eof;
+ _test_eof32: cs = 32; goto _test_eof;
+ _test_eof33: cs = 33; goto _test_eof;
+ _test_eof34: cs = 34; goto _test_eof;
+ _test_eof35: cs = 35; goto _test_eof;
+ _test_eof36: cs = 36; goto _test_eof;
+ _test_eof37: cs = 37; goto _test_eof;
+ _test_eof38: cs = 38; goto _test_eof;
+ _test_eof39: cs = 39; goto _test_eof;
+ _test_eof40: cs = 40; goto _test_eof;
+ _test_eof41: cs = 41; goto _test_eof;
+ _test_eof42: cs = 42; goto _test_eof;
+ _test_eof43: cs = 43; goto _test_eof;
+ _test_eof44: cs = 44; goto _test_eof;
+ _test_eof45: cs = 45; goto _test_eof;
+ _test_eof46: cs = 46; goto _test_eof;
+ _test_eof47: cs = 47; goto _test_eof;
+ _test_eof48: cs = 48; goto _test_eof;
+ _test_eof49: cs = 49; goto _test_eof;
+ _test_eof50: cs = 50; goto _test_eof;
+ _test_eof51: cs = 51; goto _test_eof;
+ _test_eof52: cs = 52; goto _test_eof;
+ _test_eof53: cs = 53; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 116 "parser.rl"
+
+ parser->cs = cs;
+ parser->nread += p - (buffer + off);
+
+ assert(p <= pe && "buffer overflow after parsing execute");
+ assert(parser->nread <= len && "nread longer than length");
+ assert(parser->body_start <= len && "body starts after buffer end");
+ assert(parser->mark < len && "mark is after buffer end");
+ assert(parser->field_len <= len && "field has length longer than whole buffer");
+ assert(parser->field_start < len && "field starts after buffer end");
+
+ if(parser->body_start) {
+ /* final \r\n combo encountered so stop right here */
+ parser->nread++;
+ }
+
+ return(parser->nread);
+}
+
+int thin_http_parser_finish(http_parser *parser)
+{
+ int cs = parser->cs;
+
+
+ parser->cs = cs;
+
+ if (thin_http_parser_has_error(parser) ) {
+ return -1;
+ } else if (thin_http_parser_is_finished(parser) ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int thin_http_parser_has_error(http_parser *parser) {
+ return parser->cs == http_parser_error;
+}
+
+int thin_http_parser_is_finished(http_parser *parser) {
+ return parser->cs == http_parser_first_final;
+}
49 thin_parser/parser.h
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2005 Zed A. Shaw
+ * You can redistribute it and/or modify it under the same terms as Ruby.
+ */
+
+#ifndef http11_parser_h
+#define http11_parser_h
+
+#include <sys/types.h>
+
+#if defined(_WIN32)
+#include <stddef.h>
+#endif
+
+typedef void (*element_cb)(void *data, const char *at, size_t length);
+typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
+
+typedef struct http_parser {
+ int cs;
+ size_t body_start;
+ int content_len;
+ size_t nread;
+ size_t mark;
+ size_t field_start;
+ size_t field_len;
+ size_t query_start;
+
+ void *data;
+
+ field_cb http_field;
+ element_cb request_method;
+ element_cb request_uri;
+ element_cb fragment;
+ element_cb request_path;
+ element_cb query_string;
+ element_cb http_version;
+ element_cb header_done;
+
+} http_parser;
+
+int http_parser_init(http_parser *parser);
+int http_parser_finish(http_parser *parser);
+size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
+int http_parser_has_error(http_parser *parser);
+int http_parser_is_finished(http_parser *parser);
+
+#define http_parser_nread(parser) (parser)->nread
+
+#endif
BIN  thin_parser/parser.o
Binary file not shown
157 thin_parser/parser.rl
@@ -0,0 +1,157 @@
+/**
+ * Copyright (c) 2005 Zed A. Shaw
+ * You can redistribute it and/or modify it under the same terms as Ruby.
+ */
+#include "parser.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define LEN(AT, FPC) (FPC - buffer - parser->AT)
+#define MARK(M,FPC) (parser->M = (FPC) - buffer)
+#define PTR_TO(F) (buffer + parser->F)
+
+/** Machine **/
+
+%%{
+
+ machine http_parser;
+
+ action mark {MARK(mark, fpc); }
+
+
+ action start_field { MARK(field_start, fpc); }
+ action write_field {
+ parser->field_len = LEN(field_start, fpc);
+ }
+
+ action start_value { MARK(mark, fpc); }
+ action write_value {
+ if (parser->http_field != NULL) {
+ parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
+ }
+ }
+ action request_method {
+ if (parser->request_method != NULL) {
+ parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
+ }
+ }
+ action request_uri {
+ if (parser->request_uri != NULL) {
+ parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
+ }
+ }
+ action fragment {
+ if (parser->fragment != NULL) {
+ parser->fragment(parser->data, PTR_TO(mark), LEN(mark, fpc));
+ }
+ }
+
+ action start_query {MARK(query_start, fpc); }
+ action query_string {
+ if (parser->query_string != NULL) {
+ parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
+ }
+ }
+
+ action http_version {
+ if (parser->http_version != NULL) {
+ parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
+ }
+ }
+
+ action request_path {
+ if (parser->request_path != NULL) {
+ parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
+ }
+ }
+
+ action done {
+ parser->body_start = fpc - buffer + 1;
+ if (parser->header_done != NULL) {
+ parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
+ }
+ fbreak;
+ }
+
+ include http_parser_common "common.rl";
+
+}%%
+
+/** Data **/
+%% write data;
+
+int thin_http_parser_init(http_parser *parser) {
+ int cs = 0;
+ %% write init;
+ parser->cs = cs;
+ parser->body_start = 0;
+ parser->content_len = 0;
+ parser->mark = 0;
+ parser->nread = 0;
+ parser->field_len = 0;
+ parser->field_start = 0;
+
+ return(1);
+}
+
+
+/** exec **/
+size_t thin_http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
+ const char *p, *pe;
+ int cs = parser->cs;
+
+ assert(off <= len && "offset past end of buffer");
+
+ p = buffer+off;
+ pe = buffer+len;
+
+ assert(*pe == '\0' && "pointer does not end on NUL");
+ assert(pe - p == len - off && "pointers aren't same distance");
+
+
+ %% write exec;
+
+ parser->cs = cs;
+ parser->nread += p - (buffer + off);
+
+ assert(p <= pe && "buffer overflow after parsing execute");
+ assert(parser->nread <= len && "nread longer than length");
+ assert(parser->body_start <= len && "body starts after buffer end");
+ assert(parser->mark < len && "mark is after buffer end");
+ assert(parser->field_len <= len && "field has length longer than whole buffer");
+ assert(parser->field_start < len && "field starts after buffer end");
+
+ if(parser->body_start) {
+ /* final \r\n combo encountered so stop right here */
+ parser->nread++;
+ }
+
+ return(parser->nread);
+}
+
+int thin_http_parser_finish(http_parser *parser)
+{
+ int cs = parser->cs;
+
+
+ parser->cs = cs;
+
+ if (thin_http_parser_has_error(parser) ) {
+ return -1;
+ } else if (thin_http_parser_is_finished(parser) ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int thin_http_parser_has_error(http_parser *parser) {
+ return parser->cs == http_parser_error;
+}
+
+int thin_http_parser_is_finished(http_parser *parser) {
+ return parser->cs == http_parser_first_final;
+}
436 thin_parser/thin.c
@@ -0,0 +1,436 @@
+/**
+ * Mongrel Parser adpated to Thin and to play more nicely with Rack specs.
+ *
+ * Orignal version Copyright (c) 2005 Zed A. Shaw
+ * You can redistribute it and/or modify it under the same terms as Ruby.
+ */
+#include "ruby.h"
+#include "ext_help.h"
+#include <assert.h>
+#include <string.h>
+#include "parser.h"
+#include <ctype.h>
+
+static VALUE mThin;
+static VALUE cHttpParser;
+static VALUE eHttpParserError;
+
+static VALUE global_empty;
+static VALUE global_http_prefix;
+static VALUE global_request_method;
+static VALUE global_request_uri;
+static VALUE global_fragment;
+static VALUE global_query_string;
+static VALUE global_http_version;
+static VALUE global_content_length;
+static VALUE global_http_content_length;
+static VALUE global_request_path;
+static VALUE global_content_type;
+static VALUE global_http_content_type;
+static VALUE global_gateway_interface;
+static VALUE global_gateway_interface_value;
+static VALUE global_server_name;
+static VALUE global_server_port;
+static VALUE global_server_protocol;
+static VALUE global_server_protocol_value;
+static VALUE global_http_host;
+static VALUE global_port_80;
+static VALUE global_http_body;
+static VALUE global_url_scheme;
+static VALUE global_url_scheme_value;
+static VALUE global_script_name;
+static VALUE global_path_info;
+
+#define TRIE_INCREASE 30
+
+/** Defines common length and error messages for input length validation. */
+#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " # length " allowed length."
+
+/** Validates the max length of given input and throws an HttpParserError exception if over. */
+#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); }
+
+/** Defines global strings in the init method. */
+#define DEF_GLOBAL(N, val) global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N)
+
+/* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_PTR */
+#ifndef RSTRING_PTR
+#define RSTRING_PTR(s) (RSTRING(s)->ptr)
+#endif
+
+/* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_LEN */
+#ifndef RSTRING_LEN
+#define RSTRING_LEN(s) (RSTRING(s)->len)
+#endif
+
+/* Defines the maximum allowed lengths for various input elements.*/
+DEF_MAX_LENGTH(FIELD_NAME, 256);
+DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
+DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
+DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
+DEF_MAX_LENGTH(REQUEST_PATH, 1024);
+DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
+DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
+
+
+static void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
+{
+ char *ch, *end;
+ VALUE req = (VALUE)data;
+ VALUE v = Qnil;
+ VALUE f = Qnil;
+
+ VALIDATE_MAX_LENGTH(flen, FIELD_NAME);
+ VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE);
+
+ v = rb_str_new(value, vlen);
+ f = rb_str_dup(global_http_prefix);
+ f = rb_str_buf_cat(f, field, flen);
+
+ for(ch = RSTRING_PTR(f) + RSTRING_LEN(global_http_prefix), end = RSTRING_PTR(f) + RSTRING_LEN(f); ch < end; ch++) {
+ if(*ch == '-') {
+ *ch = '_';
+ } else {
+ *ch = toupper(*ch);
+ }
+ }
+
+ rb_hash_aset(req, f, v);
+}
+
+static void request_method(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE val = Qnil;
+
+ val = rb_str_new(at, length);
+ rb_hash_aset(req, global_request_method, val);
+}
+
+static void request_uri(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE val = Qnil;
+
+ VALIDATE_MAX_LENGTH(length, REQUEST_URI);
+
+ val = rb_str_new(at, length);
+ rb_hash_aset(req, global_request_uri, val);
+}
+
+static void fragment(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE val = Qnil;
+
+ VALIDATE_MAX_LENGTH(length, FRAGMENT);
+
+ val = rb_str_new(at, length);
+ rb_hash_aset(req, global_fragment, val);
+}
+
+static void request_path(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE val = Qnil;
+
+ VALIDATE_MAX_LENGTH(length, REQUEST_PATH);
+
+ val = rb_str_new(at, length);
+ rb_hash_aset(req, global_request_path, val);
+ rb_hash_aset(req, global_path_info, val);
+}
+
+static void query_string(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE val = Qnil;
+
+ VALIDATE_MAX_LENGTH(length, QUERY_STRING);
+
+ val = rb_str_new(at, length);
+ rb_hash_aset(req, global_query_string, val);
+}
+
+static void http_version(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE val = rb_str_new(at, length);
+ rb_hash_aset(req, global_http_version, val);
+}
+
+/** Finalizes the request header to have a bunch of stuff that's
+ needed. */
+
+static void header_done(void *data, const char *at, size_t length)
+{
+ VALUE req = (VALUE)data;
+ VALUE temp = Qnil;
+ VALUE ctype = Qnil;
+ VALUE clen = Qnil;
+ VALUE body = Qnil;
+ char *colon = NULL;
+
+ clen = rb_hash_aref(req, global_http_content_length);
+ if(clen != Qnil) {
+ rb_hash_aset(req, global_content_length, clen);
+ rb_hash_delete(req, global_http_content_length);
+ }
+
+ ctype = rb_hash_aref(req, global_http_content_type);
+ if(ctype != Qnil) {
+ rb_hash_aset(req, global_content_type, ctype);
+ rb_hash_delete(req, global_http_content_type);
+ }
+
+ rb_hash_aset(req, global_gateway_interface, global_gateway_interface_value);
+ if((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
+ /* ruby better close strings off with a '\0' dammit */
+ colon = strchr(RSTRING_PTR(temp), ':');
+ if(colon != NULL) {
+ rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING_PTR(temp)));
+ rb_hash_aset(req, global_server_port,
+ rb_str_substr(temp, colon - RSTRING_PTR(temp)+1,
+ RSTRING_LEN(temp)));
+ } else {
+ rb_hash_aset(req, global_server_name, temp);
+ rb_hash_aset(req, global_server_port, global_port_80);
+ }
+ }
+
+ /* grab the initial body and stuff it into the hash */
+ if(length > 0) {
+ body = rb_hash_aref(req, global_http_body);
+ rb_io_write(body, rb_str_new(at, length));
+ }
+
+ /* according to Rack specs, query string must be empty string if none */
+ if (rb_hash_aref(req, global_query_string) == Qnil) {
+ rb_hash_aset(req, global_query_string, global_empty);
+ }
+ if (rb_hash_aref(req, global_path_info) == Qnil) {
+ rb_hash_aset(req, global_path_info, global_empty);
+ }
+
+ /* set some constants */
+ rb_hash_aset(req, global_server_protocol, global_server_protocol_value);
+ rb_hash_aset(req, global_url_scheme, global_url_scheme_value);
+ rb_hash_aset(req, global_script_name, global_empty);
+}
+
+
+void Thin_HttpParser_free(void *data) {
+ TRACE();
+
+ if(data) {
+ free(data);
+ }
+}
+
+
+VALUE Thin_HttpParser_alloc(VALUE klass)
+{
+ VALUE obj;
+ http_parser *hp = ALLOC_N(http_parser, 1);
+ TRACE();
+ hp->http_field = http_field;
+ hp->request_method = request_method;
+ hp->request_uri = request_uri;
+ hp->fragment = fragment;
+ hp->request_path = request_path;
+ hp->query_string = query_string;
+ hp->http_version = http_version;
+ hp->header_done = header_done;
+ thin_http_parser_init(hp);
+
+ obj = Data_Wrap_Struct(klass, NULL, Thin_HttpParser_free, hp);
+
+ return obj;
+}
+
+
+/**
+ * call-seq:
+ * parser.new -> parser
+ *
+ * Creates a new parser.
+ */
+VALUE Thin_HttpParser_init(VALUE self)
+{
+ http_parser *http = NULL;
+ DATA_GET(self, http_parser, http);
+ thin_http_parser_init(http);
+
+ return self;
+}
+
+
+/**
+ * call-seq:
+ * parser.reset -> nil
+ *
+ * Resets the parser to it's initial state so that you can reuse it
+ * rather than making new ones.
+ */
+VALUE Thin_HttpParser_reset(VALUE self)
+{
+ http_parser *http = NULL;
+ DATA_GET(self, http_parser, http);
+ thin_http_parser_init(http);
+
+ return Qnil;
+}
+
+
+/**
+ * call-seq:
+ * parser.finish -> true/false
+ *
+ * Finishes a parser early which could put in a "good" or bad state.
+ * You should call reset after finish it or bad things will happen.
+ */
+VALUE Thin_HttpParser_finish(VALUE self)
+{
+ http_parser *http = NULL;
+ DATA_GET(self, http_parser, http);
+ thin_http_parser_finish(http);
+
+ return thin_http_parser_is_finished(http) ? Qtrue : Qfalse;
+}
+
+
+/**
+ * call-seq:
+ * parser.execute(req_hash, data, start) -> Integer
+ *
+ * Takes a Hash and a String of data, parses the String of data filling in the Hash
+ * returning an Integer to indicate how much of the data has been read. No matter
+ * what the return value, you should call HttpParser#finished? and HttpParser#error?
+ * to figure out if it's done parsing or there was an error.
+ *
+ * This function now throws an exception when there is a parsing error. This makes
+ * the logic for working with the parser much easier. You can still test for an
+ * error, but now you need to wrap the parser with an exception handling block.
+ *
+ * The third argument allows for parsing a partial request and then continuing
+ * the parsing from that position. It needs all of the original data as well
+ * so you have to append to the data buffer as you read.
+ */
+VALUE Thin_HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
+{
+ http_parser *http = NULL;
+ int from = 0;
+ char *dptr = NULL;
+ long dlen = 0;
+
+ DATA_GET(self, http_parser, http);
+
+ from = FIX2INT(start);
+ dptr = RSTRING_PTR(data);
+ dlen = RSTRING_LEN(data);
+
+ if(from >= dlen) {
+ rb_raise(eHttpParserError, "Requested start is after data buffer end.");
+ } else {
+ http->data = (void *)req_hash;
+ thin_http_parser_execute(http, dptr, dlen, from);
+
+ VALIDATE_MAX_LENGTH(http_parser_nread(http), HEADER);
+
+ if(thin_http_parser_has_error(http)) {
+ rb_raise(eHttpParserError, "Invalid HTTP format, parsing fails.");
+ } else {
+ return INT2FIX(http_parser_nread(http));
+ }
+ }
+}
+
+
+
+/**
+ * call-seq:
+ * parser.error? -> true/false
+ *
+ * Tells you whether the parser is in an error state.
+ */
+VALUE Thin_HttpParser_has_error(VALUE self)
+{
+ http_parser *http = NULL;
+ DATA_GET(self, http_parser, http);
+
+ return thin_http_parser_has_error(http) ? Qtrue : Qfalse;
+}
+
+
+/**
+ * call-seq:
+ * parser.finished? -> true/false
+ *
+ * Tells you whether the parser is finished or not and in a good state.
+ */
+VALUE Thin_HttpParser_is_finished(VALUE self)
+{
+ http_parser *http = NULL;
+ DATA_GET(self, http_parser, http);
+
+ return thin_http_parser_is_finished(http) ? Qtrue : Qfalse;
+}
+
+
+/**
+ * call-seq:
+ * parser.nread -> Integer
+ *
+ * Returns the amount of data processed so far during this processing cycle. It is
+ * set to 0 on initialize or reset calls and is incremented each time execute is called.
+ */
+VALUE Thin_HttpParser_nread(VALUE self)
+{
+ http_parser *http = NULL;
+ DATA_GET(self, http_parser, http);
+
+ return INT2FIX(http->nread);
+}
+
+void Init_thin_parser()
+{
+
+ mThin = rb_define_module("Thin");
+
+ DEF_GLOBAL(empty, "");
+ DEF_GLOBAL(http_prefix, "HTTP_");
+ DEF_GLOBAL(request_method, "REQUEST_METHOD");
+ DEF_GLOBAL(request_uri, "REQUEST_URI");
+ DEF_GLOBAL(fragment, "FRAGMENT");
+ DEF_GLOBAL(query_string, "QUERY_STRING");
+ DEF_GLOBAL(http_version, "HTTP_VERSION");
+ DEF_GLOBAL(request_path, "REQUEST_PATH");
+ DEF_GLOBAL(content_length, "CONTENT_LENGTH");
+ DEF_GLOBAL(http_content_length, "HTTP_CONTENT_LENGTH");
+ DEF_GLOBAL(content_type, "CONTENT_TYPE");
+ DEF_GLOBAL(http_content_type, "HTTP_CONTENT_TYPE");
+ DEF_GLOBAL(gateway_interface, "GATEWAY_INTERFACE");
+ DEF_GLOBAL(gateway_interface_value, "CGI/1.2");
+ DEF_GLOBAL(server_name, "SERVER_NAME");
+ DEF_GLOBAL(server_port, "SERVER_PORT");
+ DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
+ DEF_GLOBAL(server_protocol_value, "HTTP/1.1");
+ DEF_GLOBAL(http_host, "HTTP_HOST");
+ DEF_GLOBAL(port_80, "80");
+ DEF_GLOBAL(http_body, "rack.input");
+ DEF_GLOBAL(url_scheme, "rack.url_scheme");
+ DEF_GLOBAL(url_scheme_value, "http");
+ DEF_GLOBAL(script_name, "SCRIPT_NAME");
+ DEF_GLOBAL(path_info, "PATH_INFO");
+
+ eHttpParserError = rb_define_class_under(mThin, "InvalidRequest", rb_eIOError);
+
+ cHttpParser = rb_define_class_under(mThin, "HttpParser", rb_cObject);
+ rb_define_alloc_func(cHttpParser, Thin_HttpParser_alloc);
+ rb_define_method(cHttpParser, "initialize", Thin_HttpParser_init,0);
+ rb_define_method(cHttpParser, "reset", Thin_HttpParser_reset,0);
+ rb_define_method(cHttpParser, "finish", Thin_HttpParser_finish,0);
+ rb_define_method(cHttpParser, "execute", Thin_HttpParser_execute,3);
+ rb_define_method(cHttpParser, "error?", Thin_HttpParser_has_error,0);
+ rb_define_method(cHttpParser, "finished?", Thin_HttpParser_is_finished,0);
+ rb_define_method(cHttpParser, "nread", Thin_HttpParser_nread,0);
+}
BIN  thin_parser/thin.o
Binary file not shown
BIN  thin_parser/thin_parser.bundle
Binary file not shown
73 websocket_server.rb
@@ -0,0 +1,73 @@
+require "rubygems"
+require "eventmachine"
+require "request"
+require "headers"
+
+ module ServerMethods
+ def post_init
+ puts "Received a new connection"
+ @request = Request.new
+ @msg_buffer = BufferedTokenizer.new("\377")
+ @state = :handshake
+ end
+
+ def receive_data(data)
+ process if @request.parse(data)
+ # puts @request.env.inspect
+ # puts @request.body
+
+ rescue InvalidRequest => e
+ log "!! Invalid request"
+ log_error e
+ close_connection
+ end
+
+ def process
+ case @state
+ when :handshake
+ send_handshake
+ @state = :message
+ when :message
+ #assign a single thread to process of the messages of the given user
+ EventMachine.defer(method(:process_message), method(:post_process))
+ end
+ end
+
+ def send_handshake
+ headers = Headers.new
+ headers['Upgrade'] = "WebSocket"
+ headers['Connection'] = "Upgrade"
+ headers['WebSocket-Origin'] = @request.env["HTTP_ORIGIN"]
+ headers['WebSocket-Location'] = "ws://#{@request.env["HTTP_HOST"]}/"
+
+ result = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n#{headers.to_s}\r\n"
+ puts "sending handshake..."
+ send_data(result)
+ end
+
+ def process_message
+ puts "processing messages"
+ output = []
+
+ #this will go thru all messages in stack
+ @msg_buffer.extract(@request.messages).each do |msg|
+ puts "received #{msg}"
+ output << msg
+ end
+
+ output
+ end
+
+ def post_process(result)
+ puts "sending #{result.join}"
+ result.each {|msg| send_data("\000#{msg}\377") }
+
+ #clears the body after processing messages
+ @request.messages = ""
+ end
+
+ end
+
+ EventMachine::run {
+ EventMachine::start_server "localhost", 2200, ServerMethods
+ }
Please sign in to comment.
Something went wrong with that request. Please try again.