Revision 40c0f755

View differences:

configure
4 4

  
5 5
# Fancy colors used to beautify the output a bit.
6 6
#
7
if [ "$NOCOLOR" ] ; then
8
    NORMAL=""
9
    BOLD=""
10
    RED=""
11
    YELLOW=""
12
    GREEN=""
13
else
14
    NORMAL='\\033[0m'
15
    BOLD='\\033[01;1m'
16
    RED='\\033[01;91m'
17
    YELLOW='\\033[00;33m'
18
    GREEN='\\033[01;92m'
19
fi
7
NORMAL=""
8
BOLD=""
9
RED=""
10
YELLOW=""
11
GREEN=""
20 12

  
21 13
EXIT_SUCCESS=0
22 14
EXIT_FAILURE=1
deps/libebb/.gitignore
1
*.o
2
examples/hello_world
3
test_request_parser
4
ebb_request_parser.c
5
tags
deps/libebb/LICENSE
1
Copyright (c) 2008 Ryan Dahl (ry@ndahl.us)
2

  
3
Permission is hereby granted, free of charge, to any person obtaining
4
a copy of this software and associated documentation files (the
5
"Software"), to deal in the Software without restriction, including
6
without limitation the rights to use, copy, modify, merge, publish,
7
distribute, sublicense, and/or sell copies of the Software, and to
8
permit persons to whom the Software is furnished to do so, subject to
9
the following conditions:
10

  
11
The above copyright notice and this permission notice shall be
12
included in all copies or substantial portions of the Software.
13

  
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
21

  
deps/libebb/README
1
see doc/index.html and examples/hello_world.c for explanation
2

  
3
webpage: http://tinyclouds.org/libebb/
4
git repository: http://github.com/ry/libebb/tree/master
5

  
6
To build libebb please edit config.mk to reflect your system's parameters.
7

  
deps/libebb/config.mk
1
PREFIX = $(HOME)/local/libebb
2

  
3
# libev
4
EVINC  = $(HOME)/local/libev/include
5
EVLIB  = $(HOME)/local/libev/lib
6
EVLIBS = -L${EVLIB} -lev
7

  
8
# GnuTLS, comment if you don't want it (necessary for HTTPS)
9
GNUTLSLIB   = /usr/lib
10
GNUTLSINC   = /usr/include
11
GNUTLSLIBS  = -L${GNUTLSLIB} -lgnutls
12
GNUTLSFLAGS = -DHAVE_GNUTLS
13

  
14
# includes and libs
15
INCS = -I${EVINC} -I${GNUTLSINC}
16
LIBS = ${EVLIBS} ${GNUTLSLIBS} -lefence
17

  
18
# flags
19
CPPFLAGS = -DVERSION=\"$(VERSION)\" ${GNUTLSFLAGS}
20
CFLAGS   = -O2 -g -Wall ${INCS} ${CPPFLAGS} -fPIC
21
LDFLAGS  = -s ${LIBS}
22
LDOPT    = -shared
23
SUFFIX   = so
24
SONAME   = -Wl,-soname,$(OUTPUT_LIB)
25

  
26
# Solaris
27
#CFLAGS  = -fast ${INCS} -DVERSION=\"$(VERSION)\" -fPIC
28
#LDFLAGS = ${LIBS}
29
#SONAME  = 
30

  
31
# Darwin
32
# LDOPT  = -dynamiclib 
33
# SUFFIX = dylib
34
# SONAME = -current_version $(VERSION) -compatibility_version $(VERSION)
35

  
36
# compiler and linker
37
CC = cc
38
RANLIB = ranlib
deps/libebb/doc/index.html
1

  
2
<html>
3
  <style>
4
    body {
5
      background: #fff;
6
      color: #2e3436;
7
      font-size: 12pt;
8
      line-height: 16pt;
9
  /*  font-family: Palatino;  */
10
      margin: 3em 0 3em 3em; 
11
    }
12

  
13
    code, pre {
14
    }
15

  
16
    #contents {
17
      max-width: 40em;
18
    }
19

  
20
    ul {
21
      padding-left: 0;
22
    }
23

  
24
    li {
25
      margin-top: 0.5em;
26
      margin-bottom: 0.5em;
27
    }
28

  
29
    p {
30
      text-align: left;
31
    }
32

  
33

  
34
    img {
35
      float: left;
36
      margin: 0 1em 1em 0;
37
    }
38

  
39
    p { clear: both; }
40
  </style>
41
  <body> <div id="contents">
42
    <img src="icon.png"/>
43
    <h1>libebb</h1>
44

  
45
    <p>
46
      libebb is a lightweight HTTP server library for C.  It lays the
47
      foundation for writing a web server by providing the socket juggling
48
      and request parsing. By implementing the HTTP/1.1 grammar provided in
49
      RFC2612,  libebb understands most most valid HTTP/1.1 connections
50
      (persistent, pipelined, and chunked requests included) and rejects
51
      invalid or malicious requests.  libebb supports SSL over HTTP.  
52
    </p>
53

  
54
    <p>
55
      The library embraces a minimalistic single-threaded evented design.
56
      No control is removed from the user. For example, all allocations are
57
      done through callbacks so that the user might implement in optimal
58
      ways for their specific application.  By design libebb is not
59
      thread-safe and all provided callbacks must not block.  libebb uses
60
      the <a href="http://libev.schmorp.de/bench.html">high-performance</a>
61
      libev event loop, but does not control it. The user of the library may
62
      start and stop the loop at will, they may attach thier own watchers. 
63
    </p>
64

  
65
    <p>
66
      libebb depends on POSIX sockets, libev, and optionally GnuTLS. 
67
    </p>
68

  
69
    <p>
70
      libebb is in the early stages of development and probably contains
71
      many bugs. The API is subject to radical changes.  If you're
72
      interested <a href="http://github.com/ry/libebb/tree/master">checkout
73
        the source code</a> and <a
74
        href="http://groups.google.com/group/ebbebb">join the mailing
75
        list</a>.  A release will be made when it proves stable.
76
    </p>
77

  
78
    <p>libebb is released under <a
79
      href="http://www.gnu.org/licenses/license-list.html#X11License">the
80
      X11 license</a>.</p>
81

  
82
    <h2>Usage</h2>
83

  
84
    <p>
85
      libebb is a simple API, mostly it is providing callbacks.  There are
86
      two types of callbacks that one will work with: 
87
    </p>
88

  
89
    <ul>
90
      <li>callbacks to allocate and initialize data for libebb. These are
91
      named <code>new_*</code> like <code>new_connection</code> and
92
      <code>new_request</code></li>
93
      <li>callbacks which happen on an event and might provide a pointer to
94
      a chunk of data. These are named <code>on_*</code> like
95
      <code>on_body</code> and <code>on_close</code>.</li>
96
    </ul>
97

  
98
    <p>
99
      In libebb there are three important classes: <code>ebb_server</code>,
100
      <code>ebb_connection</code>, and <code>ebb_request</code>. 
101
      Each server has many peer connections. Each peer connection may have many
102
      requests.
103
      There are two additional classes <code>ebb_buf</code> and <code>ebb_request_parser</code>
104
      which may or may not be useful.
105
    </p>
106

  
107
    <h3><code>ebb_server</code></h3>
108
    <p>
109
      <code>ebb_server</code> represents a single web server listening on a
110
      single port. The user must allocate the structure themselves, then
111
      call <code>ebb_server_init()</code> and provide a libev event loop.
112
      <code>ebb_server_set_secure()</code> will make the server understand
113
      HTTPS connections.
114
    </p>
115

  
116
    <p>
117
      After initialized the <code>ebb_server_listen_on_port()</code> can be
118
      called to open the server up to new connections. libebb does not
119
      control the event loop, it is the user's responsibility to start the
120
      event loop  (using <code>ev_loop()</code>) after
121
      <code>ebb_server_listen_on_port()</code> is called.
122
    </p>
123

  
124
    <p>
125
      To accept connections you must provide the new server with a callback
126
      called <code>new_connection</code>. This callback must return an allocated
127
      and initialized <code>ebb_connection</code> structure.     
128
      To set this callback do
129
    </p>
130

  
131
    <pre>my_server-&gt;new_connection = my_new_connection_callback;</pre>
132

  
133
    <p>
134
      Additional documentation can be found in <code>ebb.h</code>
135
    </p>
136

  
137
    <h3><code>ebb_connection</code></h3>
138

  
139
    <p>
140
      This structure contains information and callbacks for a single client
141
      connection. It is allocated and initialized through the
142
      <code>new_connection</code> callback in <code>ebb_server</code>.
143
      To initialize a newly allocated <code>ebb_connection</code> use
144
      <code>ebb_connection_init()</code>.
145
    </p>
146

  
147
    <p>
148
      After <code>ebb_connection_init()</code> is called a number of
149
      callbacks can be set: <code>new_request</code>, <code>new_buf</code>,
150
      <code>on_timeout</code>, and <code>on_close</code>.
151
    </p>
152

  
153
    <p>
154
      When an <code>ebb_connection</code> is returned to an
155
      <code>ebb_server</code>, data is immediately data is read from the
156
      socket.  This data must be stored somewhere. Because libebb is
157
      agnostic about allocation decisions, it passes this off to the user in
158
      the form of a callback: <code>connection-&gt;new_buf</code>.  This
159
      callback returns a newly allocated and initialized
160
      <code>ebb_buf</code> structure.  How much libebb attempts to read from
161
      the socket is determined by how large the returned
162
      <code>ebb_buf</code> structure is.  Using <code>new_buf</code> is
163
      optional.  By default libebb reads data into a static buffer
164
      (allocated at compile time), writing over it on each read. In many
165
      web server using the static buffer will be sufficent because callbacks
166
      made during the parsing will buffer the data elsewhere. Providing a
167
      <code>new_buf</code> callback is necessary only if you want to save
168
      the raw data coming from the socket.
169
    </p>
170

  
171
    <p>
172
      The <code>new_request</code> callback is called at the beginning of a
173
      request. It must return a newly allocated and initialized
174
      <code>ebb_request</code> structure. Because HTTP/1.1 supports <a
175
        href="http://en.wikipedia.org/wiki/HTTP_persistent_connection">peristant</a>
176
      connections, there may be many requests per connection.
177
    </p>
178

  
179
    <p>
180
      You may access the file descriptor for the client socket inside the
181
      <code>ebb_connection</code> structure. Writing the response, in valid
182
      HTTP, is the user's responsibility.  Remember, requests must be
183
      returned to client in the same order that they were received.
184
    </p>
185

  
186
    <p>
187
      A convience function, <coe>ebb_connection_write</code>, is provided
188
      which will write a single string to the peer. You may use
189
      this function or you may write to the file descriptor directly.
190
    </p>
191

  
192
    <p>
193
      To close a peer connection use
194
      <code>ebb_connnection_schedule_close()</code>. Because SSL may require
195
      some additional communication to close the connection properly, the
196
      file descriptor cannot be closed immediately. The
197
      <code>on_close</code> callback will be made when the peer socket is
198
      finally closed. 
199
      <em>Only once <code>on_close</code> is called may the
200
        user free the <code>ebb_connection</code> structure.</em> 
201
    </p>
202

  
203

  
204
    <h3><code>ebb_request</code></h3>
205

  
206
    <p>
207
      This structure provides information about a request. For example,
208
      <code>request-&gt;method == EBB_POST</code> would mean the method of
209
      the request is <code>POST</code>. There are also many callbacks
210
      which can be set to handle data from a request as it is parsed.
211
    </p>
212

  
213
    <p>
214
      The <code>on_uri</code> callback and all other
215
      <code>ebb_element_cb</code> callbacks provide pointers to request
216
      data.  The annoying thing is they do not necessarily provide a
217
      complete string.  This is because the reads from the socket may not
218
      contain an entire request and for efficency libebb does not attempt to
219
      buffer the data.  Theoretically, one might receive an
220
      <code>on_uri</code> callback 10 times, each providing just a single
221
      character of the request's URI.  See <code>ebb_request_parser.h</code> for
222
      a full list of callbacks that you may provide. (If you don't set them,
223
      they are ignored.)
224
    </p>
225

  
226
    <p>
227
      The <code>on_complete</code> callback is called at the end of
228
      each request.
229
      <em>Only once <code>on_complete</code> is called may the
230
        user free the <code>ebb_request</code> structure.</em> 
231
    </p>
232

  
233
    <h2>Example</h2>
234

  
235
    <p>
236
      A simple example is provided in <code>examples/hello_world.c</code>.
237
    </p>
238
    
239
  </div></body>
240
</html>
deps/libebb/ebb.c
1
/* This file is part of libebb.
2
 *
3
 * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us)
4
 * All rights reserved.
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 * 
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 * 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
24
 */
25
#include <assert.h>
26
#include <string.h>
27
#include <fcntl.h>
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#include <netinet/tcp.h> /* TCP_NODELAY */
31
#include <netinet/in.h>  /* inet_ntoa */
32
#include <arpa/inet.h>   /* inet_ntoa */
33
#include <unistd.h>
34
#include <stdio.h>      /* perror */
35
#include <errno.h>      /* perror */
36
#include <stdlib.h> /* for the default methods */
37
#include <ev.h>
38

  
39
#include "ebb.h"
40
#include "ebb_request_parser.h"
41
#ifdef HAVE_GNUTLS
42
# include <gnutls/gnutls.h>
43
# include "rbtree.h" /* for session_cache */
44
#endif
45

  
46
#ifndef TRUE
47
# define TRUE 1
48
#endif
49
#ifndef FALSE
50
# define FALSE 0
51
#endif 
52
#ifndef MIN
53
# define MIN(a,b) (a < b ? a : b)
54
#endif
55

  
56
#define error(FORMAT, ...) fprintf(stderr, "error: " FORMAT "\n", ##__VA_ARGS__)
57

  
58
#define CONNECTION_HAS_SOMETHING_TO_WRITE (connection->to_write != NULL)
59

  
60
static void 
61
set_nonblock (int fd)
62
{
63
  int flags = fcntl(fd, F_GETFL, 0);
64
  int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
65
  assert(0 <= r && "Setting socket non-block failed!");
66
}
67

  
68
static ssize_t 
69
nosigpipe_push(void *data, const void *buf, size_t len)
70
{
71
  int fd = (int)data;
72
  int flags = 0;
73
#ifdef MSG_NOSIGNAL
74
  flags = MSG_NOSIGNAL;
75
#endif
76
  return send(fd, buf, len, flags);
77
}
78

  
79
static void 
80
close_connection(ebb_connection *connection)
81
{
82
#ifdef HAVE_GNUTLS
83
  if(connection->server->secure)
84
    ev_io_stop(connection->server->loop, &connection->handshake_watcher);
85
#endif
86
  ev_io_stop(connection->server->loop, &connection->read_watcher);
87
  ev_io_stop(connection->server->loop, &connection->write_watcher);
88
  ev_timer_stop(connection->server->loop, &connection->timeout_watcher);
89

  
90
  if(0 > close(connection->fd))
91
    error("problem closing connection fd");
92

  
93
  connection->open = FALSE;
94

  
95
  if(connection->on_close)
96
    connection->on_close(connection);
97
  /* No access to the connection past this point! 
98
   * The user is allowed to free in the callback
99
   */
100
}
101

  
102
#ifdef HAVE_GNUTLS
103
#define GNUTLS_NEED_WRITE (gnutls_record_get_direction(connection->session) == 1)
104
#define GNUTLS_NEED_READ (gnutls_record_get_direction(connection->session) == 0)
105

  
106
#define EBB_MAX_SESSION_KEY 32
107
#define EBB_MAX_SESSION_VALUE 512
108

  
109
struct session_cache {
110
  struct rbtree_node_t node;
111

  
112
  gnutls_datum_t key;
113
  gnutls_datum_t value;
114

  
115
  char key_storage[EBB_MAX_SESSION_KEY];
116
  char value_storage[EBB_MAX_SESSION_VALUE];
117
};
118

  
119
static int 
120
session_cache_compare (void *left, void *right) 
121
{
122
  gnutls_datum_t *left_key = left;
123
  gnutls_datum_t *right_key = right;
124
  if(left_key->size < right_key->size)
125
    return -1;
126
  else if(left_key->size > right_key->size)
127
    return 1;
128
  else
129
    return memcmp( left_key->data
130
                 , right_key->data
131
                 , MIN(left_key->size, right_key->size)
132
                 );
133
}
134

  
135
static int
136
session_cache_store(void *data, gnutls_datum_t key, gnutls_datum_t value)
137
{
138
  rbtree tree = data;
139

  
140
  if( tree == NULL
141
   || key.size > EBB_MAX_SESSION_KEY
142
   || value.size > EBB_MAX_SESSION_VALUE
143
    ) return -1;
144

  
145
  struct session_cache *cache = gnutls_malloc(sizeof(struct session_cache));
146

  
147
  memcpy (cache->key_storage, key.data, key.size);
148
  cache->key.size = key.size;
149
  cache->key.data = (void*)cache->key_storage;
150

  
151
  memcpy (cache->value_storage, value.data, value.size);
152
  cache->value.size = value.size;
153
  cache->value.data = (void*)cache->value_storage;
154

  
155
  cache->node.key = &cache->key;
156
  cache->node.value = &cache;
157

  
158
  rbtree_insert(tree, (rbtree_node)cache);
159

  
160
  //printf("session_cache_store\n");
161

  
162
  return 0;
163
}
164

  
165
static gnutls_datum_t
166
session_cache_retrieve (void *data, gnutls_datum_t key)
167
{
168
  rbtree tree = data;
169
  gnutls_datum_t res = { NULL, 0 };
170
  struct session_cache *cache = rbtree_lookup(tree, &key);
171

  
172
  if(cache == NULL)
173
    return res;
174

  
175
  res.size = cache->value.size;
176
  res.data = gnutls_malloc (res.size);
177
  if(res.data == NULL)
178
    return res;
179

  
180
  memcpy(res.data, cache->value.data, res.size);
181

  
182
  //printf("session_cache_retrieve\n");
183

  
184
  return res;
185
}
186

  
187
static int
188
session_cache_remove (void *data, gnutls_datum_t key)
189
{
190
  rbtree tree = data;
191

  
192
  if(tree == NULL)
193
    return -1;
194

  
195
  struct session_cache *cache = (struct session_cache *)rbtree_delete(tree, &key);
196
  if(cache == NULL)
197
    return -1;
198

  
199
  gnutls_free(cache);
200

  
201
  //printf("session_cache_remove\n");
202

  
203
  return 0;
204
}
205

  
206
static void 
207
on_handshake(struct ev_loop *loop ,ev_io *watcher, int revents)
208
{
209
  ebb_connection *connection = watcher->data;
210

  
211
  //printf("on_handshake\n");
212

  
213
  assert(ev_is_active(&connection->timeout_watcher));
214
  assert(!ev_is_active(&connection->read_watcher));
215
  assert(!ev_is_active(&connection->write_watcher));
216

  
217
  if(EV_ERROR & revents) {
218
    error("on_handshake() got error event, closing connection.n");
219
    goto error;
220
  }
221

  
222
  int r = gnutls_handshake(connection->session);
223
  if(r < 0) {
224
    if(gnutls_error_is_fatal(r)) goto error;
225
    if(r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
226
      ev_io_set( watcher
227
               , connection->fd
228
               , (GNUTLS_NEED_WRITE ? EV_WRITE : EV_READ)
229
               );
230
    return;
231
  }
232

  
233
  ebb_connection_reset_timeout(connection);
234
  ev_io_stop(loop, watcher);
235

  
236
  ev_io_start(loop, &connection->read_watcher);
237
  if(CONNECTION_HAS_SOMETHING_TO_WRITE)
238
    ev_io_start(loop, &connection->write_watcher);
239

  
240
  return;
241
error:
242
  close_connection(connection);
243
}
244

  
245
#endif /* HAVE_GNUTLS */
246

  
247

  
248
/* Internal callback 
249
 * called by connection->timeout_watcher
250
 */
251
static void 
252
on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
253
{
254
  ebb_connection *connection = watcher->data;
255

  
256
  assert(watcher == &connection->timeout_watcher);
257

  
258
  //printf("on_timeout\n");
259

  
260
  /* if on_timeout returns true, we don't time out */
261
  if(connection->on_timeout) {
262
    int r = connection->on_timeout(connection);
263

  
264
    if(r == EBB_AGAIN) {
265
      ebb_connection_reset_timeout(connection);
266
      return;
267
    }
268
  }
269

  
270
  ebb_connection_schedule_close(connection);
271
}
272

  
273
/* Internal callback 
274
 * called by connection->read_watcher
275
 */
276
static void 
277
on_readable(struct ev_loop *loop, ev_io *watcher, int revents)
278
{
279
  ebb_connection *connection = watcher->data;
280
  char recv_buffer[TCP_MAXWIN];
281
  ssize_t recved;
282

  
283
  //printf("on_readable\n");
284
  // TODO -- why is this broken?
285
  //assert(ev_is_active(&connection->timeout_watcher));
286
  assert(watcher == &connection->read_watcher);
287

  
288
  if(EV_ERROR & revents) {
289
    error("on_readable() got error event, closing connection.");
290
    goto error;
291
  }
292

  
293
#ifdef HAVE_GNUTLS
294
  assert(!ev_is_active(&connection->handshake_watcher));
295

  
296
  if(connection->server->secure) {
297
    recved = gnutls_record_recv( connection->session
298
                               , recv_buffer
299
                               , TCP_MAXWIN
300
                               );
301
    if(recved <= 0) {
302
      if(gnutls_error_is_fatal(recved)) goto error;
303
      if( (recved == GNUTLS_E_INTERRUPTED || recved == GNUTLS_E_AGAIN)
304
       && GNUTLS_NEED_WRITE
305
        ) ev_io_start(loop, &connection->write_watcher);
306
      return; 
307
    } 
308
  } else {
309
#endif /* HAVE_GNUTLS */
310

  
311
    recved = recv(connection->fd, recv_buffer, TCP_MAXWIN, 0);
312
    if(recved <= 0) goto error;
313

  
314
#ifdef HAVE_GNUTLS
315
  }
316
#endif /* HAVE_GNUTLS */
317

  
318
  ebb_connection_reset_timeout(connection);
319

  
320
  ebb_request_parser_execute(&connection->parser, recv_buffer, recved);
321

  
322
  /* parse error? just drop the client. screw the 400 response */
323
  if(ebb_request_parser_has_error(&connection->parser)) goto error;
324
  return;
325
error:
326
  ebb_connection_schedule_close(connection);
327
}
328

  
329
/* Internal callback 
330
 * called by connection->write_watcher
331
 */
332
static void 
333
on_writable(struct ev_loop *loop, ev_io *watcher, int revents)
334
{
335
  ebb_connection *connection = watcher->data;
336
  ssize_t sent;
337
  
338
  //printf("on_writable\n");
339

  
340
  assert(CONNECTION_HAS_SOMETHING_TO_WRITE);
341
  assert(connection->written <= connection->to_write_len);
342
  // TODO -- why is this broken?
343
  //assert(ev_is_active(&connection->timeout_watcher));
344
  assert(watcher == &connection->write_watcher);
345

  
346
  if(connection->to_write == 0)
347
    goto stop_writing;
348

  
349
#ifdef HAVE_GNUTLS
350
  assert(!ev_is_active(&connection->handshake_watcher));
351

  
352
  if(connection->server->secure) {
353
    sent = gnutls_record_send( connection->session
354
                             , connection->to_write + connection->written
355
                             , connection->to_write_len - connection->written
356
                             ); 
357
    if(sent < 0) {
358
      if(gnutls_error_is_fatal(sent)) goto error;
359
      if( (sent == GNUTLS_E_INTERRUPTED || sent == GNUTLS_E_AGAIN)
360
       && GNUTLS_NEED_READ
361
        ) ev_io_stop(loop, watcher);
362
      return; 
363
    }
364
  } else {
365
#endif /* HAVE_GNUTLS */
366

  
367
    sent = nosigpipe_push( (void*)connection->fd
368
                         , connection->to_write + connection->written
369
                         , connection->to_write_len - connection->written
370
                         );
371
    if(sent < 0) goto error;
372
    if(sent == 0) return;
373

  
374
#ifdef HAVE_GNUTLS
375
  }
376
#endif /* HAVE_GNUTLS */
377

  
378
  ebb_connection_reset_timeout(connection);
379

  
380
  connection->written += sent;
381

  
382
  if(connection->written == connection->to_write_len) {
383
    goto stop_writing;
384
  }
385
  return;
386
stop_writing:
387
  ev_io_stop(loop, watcher);
388
  connection->to_write = NULL;
389

  
390
  if(connection->after_write_cb)
391
    connection->after_write_cb(connection);
392
  return;
393
error:
394
  error("close connection on write.");
395
  ebb_connection_schedule_close(connection);
396
}
397

  
398
#ifdef HAVE_GNUTLS
399

  
400
static void 
401
on_goodbye_tls(struct ev_loop *loop, ev_io *watcher, int revents)
402
{
403
  ebb_connection *connection = watcher->data;
404
  assert(watcher == &connection->goodbye_tls_watcher);
405

  
406
  if(EV_ERROR & revents) {
407
    error("on_goodbye() got error event, closing connection.");
408
    goto die;
409
  }
410

  
411
  int r = gnutls_bye(connection->session, GNUTLS_SHUT_RDWR);
412
  if(r < 0) {
413
    if(gnutls_error_is_fatal(r)) goto die;
414
    if(r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
415
      ev_io_set( watcher
416
               , connection->fd
417
               , (GNUTLS_NEED_WRITE ? EV_WRITE : EV_READ)
418
               );
419
    return;
420
  }
421

  
422
die:
423
  ev_io_stop(loop, watcher);
424
  if(connection->session) 
425
    gnutls_deinit(connection->session);
426
  close_connection(connection);
427
}
428
#endif /* HAVE_GNUTLS*/
429

  
430
static void 
431
on_goodbye(struct ev_loop *loop, ev_timer *watcher, int revents)
432
{
433
  ebb_connection *connection = watcher->data;
434
  assert(watcher == &connection->goodbye_watcher);
435

  
436
  close_connection(connection);
437
}
438

  
439

  
440
static ebb_request* 
441
new_request_wrapper(void *data)
442
{
443
  ebb_connection *connection = data;
444
  if(connection->new_request)
445
    return connection->new_request(connection);
446
  return NULL;
447
}
448

  
449
/* Internal callback 
450
 * Called by server->connection_watcher.
451
 */
452
static void 
453
on_connection(struct ev_loop *loop, ev_io *watcher, int revents)
454
{
455
  ebb_server *server = watcher->data;
456

  
457
  //printf("on connection!\n");
458

  
459
  assert(server->listening);
460
  assert(server->loop == loop);
461
  assert(&server->connection_watcher == watcher);
462
  
463
  if(EV_ERROR & revents) {
464
    error("on_connection() got error event, closing server.");
465
    ebb_server_unlisten(server);
466
    return;
467
  }
468
  
469
  struct sockaddr_in addr; // connector's address information
470
  socklen_t addr_len = sizeof(addr); 
471
  int fd = accept( server->fd
472
                 , (struct sockaddr*) & addr
473
                 , & addr_len
474
                 );
475
  if(fd < 0) {
476
    perror("accept()");
477
    return;
478
  }
479

  
480
  ebb_connection *connection = NULL;
481
  if(server->new_connection)
482
    connection = server->new_connection(server, &addr);
483
  if(connection == NULL) {
484
    close(fd);
485
    return;
486
  } 
487
  
488
  set_nonblock(fd);
489
  connection->fd = fd;
490
  connection->open = TRUE;
491
  connection->server = server;
492
  memcpy(&connection->sockaddr, &addr, addr_len);
493
  if(server->port[0] != '\0')
494
    connection->ip = inet_ntoa(connection->sockaddr.sin_addr);  
495

  
496
#ifdef SO_NOSIGPIPE
497
  int arg = 1;
498
  setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &arg, sizeof(int));
499
#endif
500

  
501
#ifdef HAVE_GNUTLS
502
  if(server->secure) {
503
    gnutls_init(&connection->session, GNUTLS_SERVER);
504
    gnutls_transport_set_lowat(connection->session, 0); 
505
    gnutls_set_default_priority(connection->session);
506
    gnutls_credentials_set(connection->session, GNUTLS_CRD_CERTIFICATE, connection->server->credentials);
507

  
508
    gnutls_transport_set_ptr(connection->session, (gnutls_transport_ptr) fd); 
509
    gnutls_transport_set_push_function(connection->session, nosigpipe_push);
510

  
511
    gnutls_db_set_ptr (connection->session, &server->session_cache);
512
    gnutls_db_set_store_function (connection->session, session_cache_store);
513
    gnutls_db_set_retrieve_function (connection->session, session_cache_retrieve);
514
    gnutls_db_set_remove_function (connection->session, session_cache_remove);
515
  }
516

  
517
  ev_io_set(&connection->handshake_watcher, connection->fd, EV_READ | EV_WRITE);
518
#endif /* HAVE_GNUTLS */
519

  
520
  /* Note: not starting the write watcher until there is data to be written */
521
  ev_io_set(&connection->write_watcher, connection->fd, EV_WRITE);
522
  ev_io_set(&connection->read_watcher, connection->fd, EV_READ);
523
  /* XXX: seperate error watcher? */
524

  
525
  ev_timer_again(loop, &connection->timeout_watcher);
526

  
527
#ifdef HAVE_GNUTLS
528
  if(server->secure) {
529
    ev_io_start(loop, &connection->handshake_watcher);
530
    return;
531
  }
532
#endif
533

  
534
  ev_io_start(loop, &connection->read_watcher);
535
}
536

  
537
/**
538
 * Begin the server listening on a file descriptor.  This DOES NOT start the
539
 * event loop.  Start the event loop after making this call.
540
 */
541
int 
542
ebb_server_listen_on_fd(ebb_server *server, const int fd)
543
{
544
  assert(server->listening == FALSE);
545

  
546
  if (listen(fd, EBB_MAX_CONNECTIONS) < 0) {
547
    perror("listen()");
548
    return -1;
549
  }
550
  
551
  set_nonblock(fd); /* XXX superfluous? */
552
  
553
  server->fd = fd;
554
  server->listening = TRUE;
555
  
556
  ev_io_set (&server->connection_watcher, server->fd, EV_READ);
557
  ev_io_start (server->loop, &server->connection_watcher);
558
  
559
  return server->fd;
560
}
561

  
562

  
563
/**
564
 * Begin the server listening on a file descriptor This DOES NOT start the
565
 * event loop. Start the event loop after making this call.
566
 */
567
int 
568
ebb_server_listen_on_port(ebb_server *server, const int port)
569
{
570
  int fd = -1;
571
  struct linger ling = {0, 0};
572
  struct sockaddr_in addr;
573
  int flags = 1;
574
  
575
  if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
576
    perror("socket()");
577
    goto error;
578
  }
579
  
580
  flags = 1;
581
  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
582
  setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
583
  setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
584

  
585
  /* XXX: Sending single byte chunks in a response body? Perhaps there is a
586
   * need to enable the Nagel algorithm dynamically. For now disabling.
587
   */
588
  setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
589
  
590
  /* the memset call clears nonstandard fields in some impementations that
591
   * otherwise mess things up.
592
   */
593
  memset(&addr, 0, sizeof(addr));
594
  
595
  addr.sin_family = AF_INET;
596
  addr.sin_port = htons(port);
597
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
598
  
599
  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
600
    perror("bind()");
601
    goto error;
602
  }
603
  
604
  int ret = ebb_server_listen_on_fd(server, fd);
605
  if (ret >= 0) {
606
    sprintf(server->port, "%d", port);
607
  }
608
  return ret;
609
error:
610
  if(fd > 0) close(fd);
611
  return -1;
612
}
613

  
614
/**
615
 * Stops the server. Will not accept new connections.  Does not drop
616
 * existing connections.
617
 */
618
void 
619
ebb_server_unlisten(ebb_server *server)
620
{
621
  if(server->listening) {
622
    ev_io_stop(server->loop, &server->connection_watcher);
623
    close(server->fd);
624
    server->port[0] = '\0';
625
    server->listening = FALSE;
626
  }
627
}
628

  
629
/**
630
 * Initialize an ebb_server structure.  After calling ebb_server_init set
631
 * the callback server->new_connection and, optionally, callback data
632
 * server->data.  The new connection MUST be initialized with
633
 * ebb_connection_init before returning it to the server.
634
 *
635
 * @param server the server to initialize
636
 * @param loop a libev loop
637
 */
638
void 
639
ebb_server_init(ebb_server *server, struct ev_loop *loop)
640
{
641
  server->loop = loop;
642
  server->listening = FALSE;
643
  server->port[0] = '\0';
644
  server->fd = -1;
645
  server->connection_watcher.data = server;
646
  ev_init (&server->connection_watcher, on_connection);
647
  server->secure = FALSE;
648

  
649
#ifdef HAVE_GNUTLS
650
  rbtree_init(&server->session_cache, session_cache_compare);
651
  server->credentials = NULL;
652
#endif
653

  
654
  server->new_connection = NULL;
655
  server->data = NULL;
656
}
657

  
658

  
659
#ifdef HAVE_GNUTLS
660
/* similar to server_init. 
661
 *
662
 * the user of secure server might want to set additional callbacks from
663
 * GNUTLS. In particular 
664
 * gnutls_global_set_mem_functions() 
665
 * gnutls_global_set_log_function()
666
 * Also see the note above ebb_connection_init() about setting gnutls cache
667
 * access functions
668
 *
669
 * cert_file: the filename of a PEM certificate file
670
 *
671
 * key_file: the filename of a private key. Currently only PKCS-1 encoded
672
 * RSA and DSA private keys are accepted. 
673
 */
674
int 
675
ebb_server_set_secure (ebb_server *server, const char *cert_file, const char *key_file)
676
{
677
  server->secure = TRUE;
678
  gnutls_global_init();
679
  gnutls_certificate_allocate_credentials(&server->credentials);
680
  /* todo gnutls_certificate_free_credentials */
681
  int r = gnutls_certificate_set_x509_key_file( server->credentials
682
                                              , cert_file
683
                                              , key_file
684
                                              , GNUTLS_X509_FMT_PEM
685
                                              );
686
  if(r < 0) {
687
    error("loading certificates");
688
    return -1;
689
  }
690
  return 1;
691
}
692
#endif /* HAVE_GNUTLS */
693

  
694
/**
695
 * Initialize an ebb_connection structure. After calling this function you
696
 * must setup callbacks for the different actions the server can take. See
697
 * server.h for which callbacks are availible. 
698
 * 
699
 * This should be called immediately after allocating space for a new
700
 * ebb_connection structure. Most likely, this will only be called within
701
 * the ebb_server->new_connection callback which you supply. 
702
 *
703
 * If using SSL do consider setting
704
 *   gnutls_db_set_retrieve_function (connection->session, _);
705
 *   gnutls_db_set_remove_function (connection->session, _);
706
 *   gnutls_db_set_store_function (connection->session, _);
707
 *   gnutls_db_set_ptr (connection->session, _);
708
 * To provide a better means of storing SSL session caches. libebb provides
709
 * only a simple default implementation. 
710
 *
711
 * @param connection the connection to initialize
712
 * @param timeout    the timeout in seconds
713
 */
714
void 
715
ebb_connection_init(ebb_connection *connection)
716
{
717
  connection->fd = -1;
718
  connection->server = NULL;
719
  connection->ip = NULL;
720
  connection->open = FALSE;
721

  
722
  ebb_request_parser_init( &connection->parser );
723
  connection->parser.data = connection;
724
  connection->parser.new_request = new_request_wrapper;
725
  
726
  ev_init (&connection->write_watcher, on_writable);
727
  connection->write_watcher.data = connection;
728
  connection->to_write = NULL;
729

  
730
  ev_init(&connection->read_watcher, on_readable);
731
  connection->read_watcher.data = connection;
732

  
733
#ifdef HAVE_GNUTLS
734
  connection->handshake_watcher.data = connection;
735
  ev_init(&connection->handshake_watcher, on_handshake);
736

  
737
  ev_init(&connection->goodbye_tls_watcher, on_goodbye_tls);
738
  connection->goodbye_tls_watcher.data = connection;
739

  
740
  connection->session = NULL;
741
#endif /* HAVE_GNUTLS */
742

  
743
  ev_timer_init(&connection->goodbye_watcher, on_goodbye, 0., 0.);
744
  connection->goodbye_watcher.data = connection;  
745

  
746
  ev_timer_init(&connection->timeout_watcher, on_timeout, 0., EBB_DEFAULT_TIMEOUT);
747
  connection->timeout_watcher.data = connection;  
748

  
749
  connection->new_request = NULL;
750
  connection->on_timeout = NULL;
751
  connection->on_close = NULL;
752
  connection->data = NULL;
753
}
754

  
755
void 
756
ebb_connection_schedule_close (ebb_connection *connection)
757
{
758
#ifdef HAVE_GNUTLS
759
  if(connection->server->secure) {
760
    ev_io_set(&connection->goodbye_tls_watcher, connection->fd, EV_READ | EV_WRITE);
761
    ev_io_start(connection->server->loop, &connection->goodbye_tls_watcher);
762
    return;
763
  }
764
#endif
765
  ev_timer_start(connection->server->loop, &connection->goodbye_watcher);
766
}
767

  
768
/* 
769
 * Resets the timeout to stay alive for another connection->timeout seconds
770
 */
771
void 
772
ebb_connection_reset_timeout(ebb_connection *connection)
773
{
774
  ev_timer_again(connection->server->loop, &connection->timeout_watcher);
775
}
776

  
777
/**
778
 * Writes a string to the socket. This is actually sets a watcher
779
 * which may take multiple iterations to write the entire string.
780
 *
781
 * This can only be called once at a time. If you call it again
782
 * while the connection is writing another buffer the ebb_connection_write
783
 * will return FALSE and ignore the request.
784
 */
785
int 
786
ebb_connection_write (ebb_connection *connection, const char *buf, size_t len, ebb_after_write_cb cb)
787
{
788
  if(ev_is_active(&connection->write_watcher))
789
    return FALSE;
790
  assert(!CONNECTION_HAS_SOMETHING_TO_WRITE);
791
  connection->to_write = buf;
792
  connection->to_write_len = len;
793
  connection->written = 0;
794
  connection->after_write_cb = cb;
795
  ev_io_start(connection->server->loop, &connection->write_watcher);
796
  return TRUE;
797
}
798

  
deps/libebb/ebb.h
1
/* This file is part of libebb.
2
 *
3
 * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us)
4
 * All rights reserved.
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 * 
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 * 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
24
 */
25
#ifndef EBB_H
26
#define EBB_H
27

  
28
#include <sys/socket.h>
29
#include <netinet/in.h>
30
#include <ev.h>
31
#ifdef HAVE_GNUTLS
32
# include <gnutls/gnutls.h>
33
# include "rbtree.h" /* for ebb_server.session_cache */
34
#endif 
35
#include "ebb_request_parser.h"
36

  
37
#define EBB_MAX_CONNECTIONS 1024
38
#define EBB_DEFAULT_TIMEOUT 30.0
39

  
40
#define EBB_AGAIN 0
41
#define EBB_STOP 1
42

  
43
typedef struct ebb_server     ebb_server;
44
typedef struct ebb_connection ebb_connection;
45
typedef void (*ebb_after_write_cb) (ebb_connection *connection); 
46
typedef void (*ebb_connection_cb)(ebb_connection *connection, void *data);
47

  
48
struct ebb_server {
49
  int fd;                                       /* ro */
50
  struct sockaddr_in sockaddr;                  /* ro */
51
  socklen_t socklen;                            /* ro */
52
  char port[6];                                 /* ro */
53
  struct ev_loop *loop;                         /* ro */
54
  unsigned listening:1;                         /* ro */
55
  unsigned secure:1;                            /* ro */
56
#ifdef HAVE_GNUTLS
57
  gnutls_certificate_credentials_t credentials; /* private */
58
  struct rbtree_t session_cache;                /* private */
59
#endif
60
  ev_io connection_watcher;                     /* private */
61

  
62
  /* Public */
63

  
64
  /* Allocates and initializes an ebb_connection.  NULL by default. */
65
  ebb_connection* (*new_connection) (ebb_server*, struct sockaddr_in*);
66

  
67
  void *data;
68
};
69

  
70
struct ebb_connection {
71
  int fd;                      /* ro */
72
  struct sockaddr_in sockaddr; /* ro */
73
  socklen_t socklen;           /* ro */ 
74
  ebb_server *server;          /* ro */
75
  char *ip;                    /* ro */
76
  unsigned open:1;             /* ro */
77

  
78
  const char *to_write;              /* ro */
79
  size_t to_write_len;               /* ro */
80
  size_t written;                    /* ro */ 
81
  ebb_after_write_cb after_write_cb; /* ro */
82

  
83
  ebb_request_parser parser;   /* private */
84
  ev_io write_watcher;         /* private */
85
  ev_io read_watcher;          /* private */
86
  ev_timer timeout_watcher;    /* private */
87
  ev_timer goodbye_watcher;    /* private */
88
#ifdef HAVE_GNUTLS
89
  ev_io handshake_watcher;     /* private */
90
  gnutls_session_t session;    /* private */
91
  ev_io goodbye_tls_watcher;       /* private */
92
#endif
93

  
94
  /* Public */
95

  
96
  ebb_request* (*new_request) (ebb_connection*); 
97

  
98
  /* Returns EBB_STOP or EBB_AGAIN. NULL by default.  */
99
  int (*on_timeout) (ebb_connection*); 
100

  
101
  void (*on_close) (ebb_connection*); 
102

  
103
  void *data;
104
};
105

  
106
void ebb_server_init (ebb_server *server, struct ev_loop *loop);
107
#ifdef HAVE_GNUTLS
108
int ebb_server_set_secure (ebb_server *server, const char *cert_file, 
109
                           const char *key_file);
110
#endif
111
int ebb_server_listen_on_port (ebb_server *server, const int port);
112
int ebb_server_listen_on_fd (ebb_server *server, const int sfd);
113
void ebb_server_unlisten (ebb_server *server);
114

  
115
void ebb_connection_init (ebb_connection *);
116
void ebb_connection_schedule_close (ebb_connection *);
117
void ebb_connection_reset_timeout (ebb_connection *);
118
int ebb_connection_write (ebb_connection *, const char *buf, size_t len, ebb_after_write_cb);
119

  
120
#endif
deps/libebb/ebb_request_parser.h
1
/* This file is part of the libebb web server library
2
 *
3
 * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us)
4
 * All rights reserved.
5
 *
6
 * This parser is based on code from Zed Shaw's Mongrel.
7
 * Copyright (c) 2005 Zed A. Shaw
8
 * 
9
 * Permission is hereby granted, free of charge, to any person obtaining
10
 * a copy of this software and associated documentation files (the
11
 * "Software"), to deal in the Software without restriction, including
12
 * without limitation the rights to use, copy, modify, merge, publish,
13
 * distribute, sublicense, and/or sell copies of the Software, and to
14
 * permit persons to whom the Software is furnished to do so, subject to
15
 * the following conditions:
16
 * 
17
 * The above copyright notice and this permission notice shall be
18
 * included in all copies or substantial portions of the Software.
19
 * 
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
27
 */
28
#ifndef ebb_request_parser_h
29
#define ebb_request_parser_h
30
#ifdef __cplusplus
31
extern "C" {
32
#endif 
33

  
34

  
35
#include <sys/types.h> 
36

  
37
typedef struct ebb_request ebb_request;
38
typedef struct ebb_request_parser  ebb_request_parser;
39
typedef void (*ebb_header_cb)(ebb_request*, const char *at, size_t length, int header_index);
40
typedef void (*ebb_element_cb)(ebb_request*, const char *at, size_t length);
41

  
42
#define EBB_MAX_MULTIPART_BOUNDARY_LEN 20
43

  
44
/* HTTP Methods */
45
#define EBB_COPY       0x00000001
46
#define EBB_DELETE     0x00000002
47
#define EBB_GET        0x00000004
48
#define EBB_HEAD       0x00000008
49
#define EBB_LOCK       0x00000010
50
#define EBB_MKCOL      0x00000020
51
#define EBB_MOVE       0x00000040
52
#define EBB_OPTIONS    0x00000080
53
#define EBB_POST       0x00000100
54
#define EBB_PROPFIND   0x00000200
55
#define EBB_PROPPATCH  0x00000400
56
#define EBB_PUT        0x00000800
57
#define EBB_TRACE      0x00001000
58
#define EBB_UNLOCK     0x00002000
59

  
60
/* Transfer Encodings */
61
#define EBB_IDENTITY   0x00000001
62
#define EBB_CHUNKED    0x00000002
63

  
64
struct ebb_request {
65
  int method;
66
  int transfer_encoding;         /* ro */
67
  int expect_continue;               /* ro */
68
  unsigned int version_major;        /* ro */
69
  unsigned int version_minor;        /* ro */
70
  int number_of_headers;             /* ro */
71
  int keep_alive;                    /* private - use ebb_request_should_keep_alive */
72
  size_t content_length;             /* ro - 0 if unknown */
73
  size_t body_read;                  /* ro */
74

  
75
  /* Public  - ordered list of callbacks */
76
  ebb_element_cb on_path;
77
  ebb_element_cb on_query_string;
78
  ebb_element_cb on_uri;
79
  ebb_element_cb on_fragment;
80
  ebb_header_cb  on_header_field;
81
  ebb_header_cb  on_header_value;
82
  void (*on_headers_complete)(ebb_request *);
83
  ebb_element_cb on_body;
84
  void (*on_complete)(ebb_request *);
85
  void *data;
86
};
87

  
88
struct ebb_request_parser {
89
  int cs;                           /* private */
90
  size_t chunk_size;                /* private */
91
  unsigned eating:1;                /* private */
92
  ebb_request *current_request;     /* ro */
93
  const char *header_field_mark; 
94
  const char *header_value_mark; 
95
  const char *query_string_mark; 
96
  const char *path_mark; 
97
  const char *uri_mark; 
98
  const char *fragment_mark; 
99

  
100
  /* Public */
101
  ebb_request* (*new_request)(void*);
102
  void *data;
103
};
104

  
105
void ebb_request_parser_init(ebb_request_parser *parser);
106
size_t ebb_request_parser_execute(ebb_request_parser *parser, const char *data, size_t len);
107
int ebb_request_parser_has_error(ebb_request_parser *parser);
108
int ebb_request_parser_is_finished(ebb_request_parser *parser);
109
void ebb_request_init(ebb_request *);
110
int ebb_request_should_keep_alive(ebb_request *request);
111
#define ebb_request_has_body(request) \
112
  (request->transfer_encoding == EBB_CHUNKED || request->content_length > 0 )
113

  
114
#ifdef __cplusplus
115
}
116
#endif 
117
#endif
deps/libebb/ebb_request_parser.rl
1
/* This file is part of the libebb web server library
2
 *
3
 * Copyright (c) 2008 Ryan Dahl (ry@ndahl.us)
4
 * All rights reserved.
5
 *
6
 * This parser is based on code from Zed Shaw's Mongrel.
7
 * Copyright (c) 2005 Zed A. Shaw
8
 * 
9
 * Permission is hereby granted, free of charge, to any person obtaining
10
 * a copy of this software and associated documentation files (the
11
 * "Software"), to deal in the Software without restriction, including
12
 * without limitation the rights to use, copy, modify, merge, publish,
13
 * distribute, sublicense, and/or sell copies of the Software, and to
14
 * permit persons to whom the Software is furnished to do so, subject to
15
 * the following conditions:
16
 * 
17
 * The above copyright notice and this permission notice shall be
18
 * included in all copies or substantial portions of the Software.
19
 * 
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
27
 */
28
#include "ebb_request_parser.h"
29

  
30
#include <stdio.h>
31
#include <assert.h>
32

  
33
static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
34
                     ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
35
                     ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
36
                     , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
37
                     ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
38
                     ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
39
                     ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
40
                     ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
41
                     };
42
#define TRUE 1
43
#define FALSE 0
44
#define MIN(a,b) (a < b ? a : b)
45

  
46
#define REMAINING (pe - p)
47
#define CURRENT (parser->current_request)
48
#define CONTENT_LENGTH (parser->current_request->content_length)
49
#define CALLBACK(FOR)                               \
50
  if(parser->FOR##_mark && CURRENT->on_##FOR) {     \
51
    CURRENT->on_##FOR( CURRENT                      \
52
                , parser->FOR##_mark                \
53
                , p - parser->FOR##_mark            \
54
                );                                  \
55
 }
56
#define HEADER_CALLBACK(FOR)                        \
57
  if(parser->FOR##_mark && CURRENT->on_##FOR) {     \
58
    CURRENT->on_##FOR( CURRENT                      \
59
                , parser->FOR##_mark                \
60
                , p - parser->FOR##_mark            \
61
                , CURRENT->number_of_headers        \
62
                );                                  \
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff