unicorn.git  about / heads / tags
Rack HTTP server for Unix and fast clients
blob c9be22e84be0d8e982be59998ae243eed471551d 4129 bytes (raw)
$ git show v0.0.0:ext/http11/http11_parser.java.rl	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
 
package org.jruby.mongrel;

import org.jruby.util.ByteList;

public class Http11Parser {

/** Machine **/

%%{
  
  machine http_parser;

  action mark {parser.mark = fpc; }

  action start_field { parser.field_start = fpc; }
  action snake_upcase_field { /* FIXME stub */ }
  action write_field { 
    parser.field_len = fpc-parser.field_start;
  }

  action start_value { parser.mark = fpc; }
  action write_value { 
    if(parser.http_field != null) {
      parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
    }
  }
  action request_method { 
    if(parser.request_method != null) 
      parser.request_method.call(parser.data, parser.mark, fpc-parser.mark);
  }
  action request_uri { 
    if(parser.request_uri != null)
      parser.request_uri.call(parser.data, parser.mark, fpc-parser.mark);
  }
  action fragment { 
    if(parser.fragment != null)
      parser.fragment.call(parser.data, parser.mark, fpc-parser.mark);
  }
  
  action start_query {parser.query_start = fpc; }
  action query_string { 
    if(parser.query_string != null)
      parser.query_string.call(parser.data, parser.query_start, fpc-parser.query_start);
  }

  action http_version {	
    if(parser.http_version != null)
      parser.http_version.call(parser.data, parser.mark, fpc-parser.mark);
  }

  action request_path {
    if(parser.request_path != null)
      parser.request_path.call(parser.data, parser.mark, fpc-parser.mark);
  }

  action done { 
    parser.body_start = fpc + 1; 
    if(parser.header_done != null)
      parser.header_done.call(parser.data, fpc + 1, pe - fpc - 1);
    fbreak;
  }

  include http_parser_common "http11_parser_common.rl";

}%%

/** Data **/
%% write data;

   public static interface ElementCB {
     public void call(Object data, int at, int length);
   }

   public static interface FieldCB {
     public void call(Object data, int field, int flen, int value, int vlen);
   }

   public static class HttpParser {
      int cs;
      int body_start;
      int content_len;
      int nread;
      int mark;
      int field_start;
      int field_len;
      int query_start;

      Object data;
      ByteList buffer;

      public FieldCB http_field;
      public ElementCB request_method;
      public ElementCB request_uri;
      public ElementCB fragment;
      public ElementCB request_path;
      public ElementCB query_string;
      public ElementCB http_version;
      public ElementCB header_done;

      public void init() {
          cs = 0;

          %% write init;

          body_start = 0;
          content_len = 0;
          mark = 0;
          nread = 0;
          field_len = 0;
          field_start = 0;
      }
   }

   public final HttpParser parser = new HttpParser();

   public int execute(ByteList buffer, int off) {
     int p, pe;
     int cs = parser.cs;
     int len = buffer.realSize;
     assert off<=len : "offset past end of buffer";

     p = off;
     pe = len;
     byte[] data = buffer.bytes;
     parser.buffer = buffer;

     %% write exec;

     parser.cs = cs;
     parser.nread += (p - 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>0) {
        /* final \r\n combo encountered so stop right here */
        %%write eof;
        parser.nread++;
     }

     return parser.nread;
   }

   public int finish() {
     int cs = parser.cs;

     %%write eof;

     parser.cs = cs;
 
    if(has_error()) {
      return -1;
    } else if(is_finished()) {
      return 1;
    } else {
      return 0;
    }
  }

  public boolean has_error() {
    return parser.cs == http_parser_error;
  }

  public boolean is_finished() {
    return parser.cs == http_parser_first_final;
  }
}

git clone https://yhbt.net/unicorn.git