iodine 0.2.7 → 0.2.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +5 -1
- data/ext/iodine/base64.c +3 -3
- data/ext/iodine/base64.h +3 -3
- data/ext/iodine/bscrypt-common.h +5 -5
- data/ext/iodine/bscrypt.h +4 -4
- data/ext/iodine/hex.c +11 -10
- data/ext/iodine/hex.h +3 -3
- data/ext/iodine/http.c +34 -27
- data/ext/iodine/http.h +15 -8
- data/ext/iodine/http1.c +63 -60
- data/ext/iodine/http1.h +10 -5
- data/ext/iodine/http1_simple_parser.c +6 -0
- data/ext/iodine/http1_simple_parser.h +10 -6
- data/ext/iodine/http_request.h +28 -22
- data/ext/iodine/http_response.c +22 -7
- data/ext/iodine/http_response.h +6 -0
- data/ext/iodine/http_response_http1.h +9 -1
- data/ext/iodine/iodine_core.c +6 -1
- data/ext/iodine/iodine_core.h +13 -6
- data/ext/iodine/iodine_http.c +6 -0
- data/ext/iodine/iodine_http.h +6 -0
- data/ext/iodine/iodine_websocket.c +23 -4
- data/ext/iodine/iodine_websocket.h +2 -2
- data/ext/iodine/libasync.c +5 -3
- data/ext/iodine/libasync.h +8 -8
- data/ext/iodine/libreact.c +8 -8
- data/ext/iodine/libreact.h +5 -5
- data/ext/iodine/libserver.c +2 -2
- data/ext/iodine/libserver.h +2 -2
- data/ext/iodine/libsock.c +2 -2
- data/ext/iodine/libsock.h +3 -3
- data/ext/iodine/mempool.h +826 -0
- data/ext/iodine/misc.c +14 -14
- data/ext/iodine/misc.h +3 -3
- data/ext/iodine/random.c +6 -6
- data/ext/iodine/random.h +3 -3
- data/ext/iodine/rb-call.c +6 -0
- data/ext/iodine/rb-call.h +2 -2
- data/ext/iodine/rb-libasync.h +5 -3
- data/ext/iodine/rb-rack-io.c +15 -3
- data/ext/iodine/rb-rack-io.h +5 -2
- data/ext/iodine/rb-registry.c +6 -0
- data/ext/iodine/rb-registry.h +2 -2
- data/ext/iodine/sha1.c +13 -11
- data/ext/iodine/sha1.h +3 -3
- data/ext/iodine/sha2.c +8 -6
- data/ext/iodine/sha2.h +3 -3
- data/ext/iodine/siphash.c +9 -2
- data/ext/iodine/siphash.h +8 -1
- data/ext/iodine/spnlock.h +9 -3
- data/ext/iodine/websockets.c +62 -38
- data/ext/iodine/websockets.h +6 -0
- data/ext/iodine/xor-crypt.c +3 -3
- data/ext/iodine/xor-crypt.h +3 -3
- data/lib/iodine/version.rb +1 -1
- metadata +3 -4
- data/ext/iodine/rb-call.c_old +0 -127
- data/ext/iodine/rb-registry_old.c_old +0 -213
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc35ddb10525599dcaacd5746e7ad1b6b5798d25
|
4
|
+
data.tar.gz: abb7a77d1f0e9e224037aea022d3b58964d24459
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47ae99c46deb8aac630e8b096a0478fb45e1d7aa732f988ca111ebcbc55e13e74fa6c816c27d4f826f89ec0de2ab82b75c0ecf5495a0d560eae54556db6dde87
|
7
|
+
data.tar.gz: 810d41cbe10ca2683eb9d6fadbd02cc66df8c6ae55cf1857be6aae4208e1988884f9b24b8240497d435d4ddd9409f7b30f1f0492a7382c0900c870d8d11651da
|
data/CHANGELOG.md
CHANGED
@@ -8,9 +8,17 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
8
8
|
|
9
9
|
***
|
10
10
|
|
11
|
+
Change log v.0.2.8
|
12
|
+
|
13
|
+
**Memory Performance**: The Websocket connection Protocol now utilizes both a C level memory pool and a local thread storage for temporary data. This helps mitigate possible memory fragmentation issues related to long running processes and long-lived objects. In addition, the socket `read` buffer was moved from the protocol object to a local thread storage (assumes pthreads and not green threads). This minimizes the memory footprint for each connection (at the expense of memory locality) and should allow Iodine to support more concurrent connections using less system resources. Last, but not least, the default message buffer per connection starts at 4Kb instead of 16Kb (grows as needed, up to `Iodine::Rack.max_msg_size`), assuming smaller messages are the norm.
|
14
|
+
|
15
|
+
**Housekeeping**: Cleaned up some code, removed old files, copied over the latest [`facil.io`](http://facil.io) library. There's probably some more housekeeping left to perform, especially anywhere where documentation is concerned. I welcome help with documentation.
|
16
|
+
|
17
|
+
***
|
18
|
+
|
11
19
|
Change log v.0.2.7
|
12
20
|
|
13
|
-
**Minor Fix**: fixed an issue where a negative number
|
21
|
+
**Minor Fix**: fixed an issue where a negative number of processes or threads would initiate a very large number of forks, promoting a system resource choke. Limited the number of threads (1023) and processes (127).
|
14
22
|
|
15
23
|
**Update**: Automated the number of processes (forks) and threads used when these are not explicitly specified. These follow the number of cores / 2.
|
16
24
|
|
data/README.md
CHANGED
@@ -33,6 +33,8 @@ Using the Iodine server is easy, simply add Iodine as a gem to your Rack applica
|
|
33
33
|
gem 'iodine', :git => 'https://github.com/boazsegev/iodine.git'
|
34
34
|
```
|
35
35
|
|
36
|
+
Iodine will calculate, when possible, a good enough default concurrency model for fast applications... this might not fit your application if you use database access or other blocking calls.
|
37
|
+
|
36
38
|
To get the most out of Iodine, consider the amount of CPU cores available and the concurrency level the application requires.
|
37
39
|
|
38
40
|
Puma's model of 16 threads and 4 processes is easily adopted and proved to provide a good enough balance for most use-cases. Use:
|
@@ -41,7 +43,9 @@ Puma's model of 16 threads and 4 processes is easily adopted and proved to provi
|
|
41
43
|
bundler exec iodine -p $PORT -t 16 -w 4
|
42
44
|
```
|
43
45
|
|
44
|
-
It should be noted that
|
46
|
+
It should be noted that automatic process scaling will cause issues with Websocket broadcast (`each`) support, ssince the `Websocket#each` method will be limited to the calling process (other clients might be connected to a different process.
|
47
|
+
|
48
|
+
I recommended that you consider using Redis to scale Websocket "events" across processes / machines. look into [plezi.io](http://www.plezi.io) for automatic Websocket scaling with Redis and Iodine.
|
45
49
|
|
46
50
|
### Writing data to the network layer
|
47
51
|
|
data/ext/iodine/base64.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
License:
|
4
|
-
subject to their own licenses.
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
+
of), which might be subject to their own licenses.
|
5
5
|
|
6
6
|
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
7
|
*/
|
data/ext/iodine/base64.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
License:
|
4
|
-
subject to their own licenses.
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
+
of), which might be subject to their own licenses.
|
5
5
|
|
6
6
|
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
7
|
*/
|
data/ext/iodine/bscrypt-common.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
License:
|
4
|
-
subject to their own licenses.
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
+
of), which might be subject to their own licenses.
|
5
5
|
|
6
6
|
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
7
|
*/
|
@@ -11,9 +11,9 @@ Feel free to copy, use and enjoy in accordance with to the license(s).
|
|
11
11
|
Environment - you can safely ignore this part... probably.
|
12
12
|
*/
|
13
13
|
|
14
|
+
#include <stdint.h>
|
14
15
|
#include <stdio.h>
|
15
16
|
#include <stdlib.h>
|
16
|
-
#include <stdint.h>
|
17
17
|
#include <string.h>
|
18
18
|
#include <time.h>
|
19
19
|
|
@@ -26,7 +26,7 @@ Environment - you can safely ignore this part... probably.
|
|
26
26
|
#ifdef __has_include
|
27
27
|
|
28
28
|
/* check for unix support */
|
29
|
-
#if __has_include(<unistd.h>)&&__has_include(<pthread.h>)
|
29
|
+
#if __has_include(<unistd.h>) && __has_include(<pthread.h>)
|
30
30
|
#define HAS_UNIX_FEATURES
|
31
31
|
#endif
|
32
32
|
|
data/ext/iodine/bscrypt.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
License:
|
4
|
-
subject to their own licenses.
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
+
of), which might be subject to their own licenses.
|
5
5
|
|
6
6
|
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
7
|
*/
|
@@ -20,8 +20,8 @@ All functions will be available using the prefix `bscrypt_`, i.e.:
|
|
20
20
|
*/
|
21
21
|
#define BSCRYPT "0.0.1"
|
22
22
|
|
23
|
-
#include "bscrypt-common.h"
|
24
23
|
#include "base64.h"
|
24
|
+
#include "bscrypt-common.h"
|
25
25
|
#include "hex.h"
|
26
26
|
#include "misc.h"
|
27
27
|
#include "random.h"
|
data/ext/iodine/hex.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
License:
|
4
|
-
subject to their own licenses.
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
+
of), which might be subject to their own licenses.
|
5
5
|
|
6
6
|
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
7
|
*/
|
@@ -24,13 +24,14 @@ Hex Conversion
|
|
24
24
|
|
25
25
|
/* Credit to Jonathan Leffler for the idea */
|
26
26
|
#define hex2i(c) \
|
27
|
-
(((c) >= '0' && (c) <= '9')
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
(((c) >= '0' && (c) <= '9') \
|
28
|
+
? ((c)-48) \
|
29
|
+
: (((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) \
|
30
|
+
? (((c) | 32) - 87) \
|
31
|
+
: ({ \
|
32
|
+
return -1; \
|
33
|
+
0; \
|
34
|
+
}))
|
34
35
|
|
35
36
|
/**
|
36
37
|
Returns 1 if the string is HEX encoded (no non-valid hex values). Returns 0 if
|
data/ext/iodine/hex.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
License:
|
4
|
-
subject to their own licenses.
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
+
of), which might be subject to their own licenses.
|
5
5
|
|
6
6
|
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
7
|
*/
|
data/ext/iodine/http.c
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
/*
|
2
|
+
copyright: Boaz segev, 2016-2017
|
3
|
+
license: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
1
7
|
#include "http.h"
|
2
8
|
|
3
9
|
/**
|
@@ -7,14 +13,14 @@ See the libc `gmtime_r` documentation for details.
|
|
7
13
|
|
8
14
|
Falls back to `gmtime_r` for dates before epoch.
|
9
15
|
*/
|
10
|
-
struct tm*
|
16
|
+
struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf) {
|
11
17
|
// static char* DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
12
18
|
// static char * Months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
13
19
|
// "Jul",
|
14
20
|
// "Aug", "Sep", "Oct", "Nov", "Dec"};
|
15
21
|
static uint8_t month_len[] = {
|
16
|
-
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
17
|
-
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
22
|
+
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // nonleap year
|
23
|
+
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // leap year
|
18
24
|
};
|
19
25
|
if (*timer < 0)
|
20
26
|
return gmtime_r(timer, tmbuf);
|
@@ -22,7 +28,7 @@ struct tm* http_gmtime(const time_t* timer, struct tm* tmbuf) {
|
|
22
28
|
tmbuf->tm_gmtoff = 0;
|
23
29
|
tmbuf->tm_zone = "UTC";
|
24
30
|
tmbuf->tm_isdst = 0;
|
25
|
-
tmbuf->tm_year = 70;
|
31
|
+
tmbuf->tm_year = 70; // tm_year == The number of years since 1900
|
26
32
|
tmbuf->tm_mon = 0;
|
27
33
|
// for seconds up to weekdays, we build up, as small values clean up larger
|
28
34
|
// values.
|
@@ -47,7 +53,7 @@ struct tm* http_gmtime(const time_t* timer, struct tm* tmbuf) {
|
|
47
53
|
tmbuf->tm_year += 100;
|
48
54
|
tmp -= DAYS_PER_100_YEARS;
|
49
55
|
if (((tmbuf->tm_year / 100) & 3) ==
|
50
|
-
0)
|
56
|
+
0) // leap century divisable by 400 => add leap
|
51
57
|
--tmp;
|
52
58
|
}
|
53
59
|
#undef DAYS_PER_100_YEARS
|
@@ -72,7 +78,7 @@ struct tm* http_gmtime(const time_t* timer, struct tm* tmbuf) {
|
|
72
78
|
while (tmp >= 365) {
|
73
79
|
tmbuf->tm_year += 1;
|
74
80
|
tmp -= 365;
|
75
|
-
if ((tmbuf->tm_year & 3) == 0) {
|
81
|
+
if ((tmbuf->tm_year & 3) == 0) { // leap year
|
76
82
|
if (tmp > 0) {
|
77
83
|
--tmp;
|
78
84
|
continue;
|
@@ -105,15 +111,15 @@ struct tm* http_gmtime(const time_t* timer, struct tm* tmbuf) {
|
|
105
111
|
return tmbuf;
|
106
112
|
}
|
107
113
|
|
108
|
-
static char*
|
109
|
-
static char*
|
114
|
+
static char *DAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
115
|
+
static char *MONTH_NAMES[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
|
110
116
|
"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "};
|
111
|
-
static const char*
|
117
|
+
static const char *GMT_STR = "GMT";
|
112
118
|
|
113
|
-
size_t http_date2str(char*
|
114
|
-
char*
|
119
|
+
size_t http_date2str(char *target, struct tm *tmbuf) {
|
120
|
+
char *pos = target;
|
115
121
|
uint16_t tmp;
|
116
|
-
*(uint32_t*)pos = *((uint32_t*)DAY_NAMES[tmbuf->tm_wday]);
|
122
|
+
*(uint32_t *)pos = *((uint32_t *)DAY_NAMES[tmbuf->tm_wday]);
|
117
123
|
pos[3] = ',';
|
118
124
|
pos[4] = ' ';
|
119
125
|
pos += 5;
|
@@ -127,7 +133,7 @@ size_t http_date2str(char* target, struct tm* tmbuf) {
|
|
127
133
|
pos += 2;
|
128
134
|
}
|
129
135
|
*(pos++) = ' ';
|
130
|
-
*(uint32_t*)pos = *((uint32_t*)MONTH_NAMES[tmbuf->tm_mon]);
|
136
|
+
*(uint32_t *)pos = *((uint32_t *)MONTH_NAMES[tmbuf->tm_mon]);
|
131
137
|
pos += 4;
|
132
138
|
// write year.
|
133
139
|
pos += http_ul2a(pos, tmbuf->tm_year + 1900);
|
@@ -145,23 +151,24 @@ size_t http_date2str(char* target, struct tm* tmbuf) {
|
|
145
151
|
pos[7] = '0' + (tmbuf->tm_sec - (tmp * 10));
|
146
152
|
pos += 8;
|
147
153
|
pos[0] = ' ';
|
148
|
-
*((uint32_t*)(pos + 1)) = *((uint32_t*)GMT_STR);
|
154
|
+
*((uint32_t *)(pos + 1)) = *((uint32_t *)GMT_STR);
|
149
155
|
pos += 4;
|
150
156
|
return pos - target;
|
151
157
|
}
|
152
158
|
|
153
159
|
/* Credit to Jonathan Leffler for the idea of a unified conditional */
|
154
|
-
#define hex_val(c)
|
155
|
-
(((c) >= '0' && (c) <= '9')
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
160
|
+
#define hex_val(c) \
|
161
|
+
(((c) >= '0' && (c) <= '9') \
|
162
|
+
? ((c)-48) \
|
163
|
+
: (((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) \
|
164
|
+
? (((c) | 32) - 87) \
|
165
|
+
: ({ \
|
166
|
+
return -1; \
|
167
|
+
0; \
|
168
|
+
}))
|
169
|
+
ssize_t http_decode_url(char *dest, const char *url_data, size_t length) {
|
170
|
+
char *pos = dest;
|
171
|
+
const char *end = url_data + length;
|
165
172
|
while (url_data < end) {
|
166
173
|
if (*url_data == '+') {
|
167
174
|
// decode space
|
@@ -179,8 +186,8 @@ ssize_t http_decode_url(char* dest, const char* url_data, size_t length) {
|
|
179
186
|
return pos - dest;
|
180
187
|
}
|
181
188
|
|
182
|
-
ssize_t http_decode_url_unsafe(char*
|
183
|
-
char*
|
189
|
+
ssize_t http_decode_url_unsafe(char *dest, const char *url_data) {
|
190
|
+
char *pos = dest;
|
184
191
|
while (*url_data) {
|
185
192
|
if (*url_data == '+') {
|
186
193
|
// decode space
|
data/ext/iodine/http.h
CHANGED
@@ -1,14 +1,21 @@
|
|
1
|
+
/*
|
2
|
+
copyright: Boaz segev, 2016-2017
|
3
|
+
license: MIT
|
1
4
|
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
2
7
|
#ifndef HTTP_H
|
3
8
|
#define HTTP_H
|
4
9
|
|
5
10
|
/* *****************************************************************************
|
6
11
|
Core include files
|
7
12
|
*/
|
13
|
+
// clang-format off
|
8
14
|
#include "libserver.h"
|
15
|
+
#include <time.h>
|
9
16
|
#include "http_request.h"
|
10
17
|
#include "http_response.h"
|
11
|
-
|
18
|
+
// clang-format on
|
12
19
|
/* *****************************************************************************
|
13
20
|
Hard Coded Settings
|
14
21
|
*/
|
@@ -37,12 +44,12 @@ typedef struct {
|
|
37
44
|
*/
|
38
45
|
size_t max_body_size;
|
39
46
|
/** the callback to be performed when requests come in. */
|
40
|
-
void (*on_request)(http_request_s*
|
47
|
+
void (*on_request)(http_request_s *request);
|
41
48
|
/**
|
42
49
|
A public folder for file transfers - allows to circumvent any application
|
43
50
|
layer server and simply serve files.
|
44
51
|
*/
|
45
|
-
const char*
|
52
|
+
const char *public_folder;
|
46
53
|
/**
|
47
54
|
The length of the public_folder string.
|
48
55
|
*/
|
@@ -72,7 +79,7 @@ See the libc `gmtime_r` documentation for details.
|
|
72
79
|
|
73
80
|
Falls back to `gmtime_r` for dates before epoch.
|
74
81
|
*/
|
75
|
-
struct tm*
|
82
|
+
struct tm *http_gmtime(const time_t *timer, struct tm *tmbuf);
|
76
83
|
|
77
84
|
/**
|
78
85
|
Writes an HTTP date string to the `target` buffer.
|
@@ -81,7 +88,7 @@ This requires _____ bytes of space to be available at the target buffer.
|
|
81
88
|
|
82
89
|
Returns the number of bytes actually written.
|
83
90
|
*/
|
84
|
-
size_t http_date2str(char*
|
91
|
+
size_t http_date2str(char *target, struct tm *tmbuf);
|
85
92
|
|
86
93
|
/**
|
87
94
|
A fast, inline alternative to `sprintf(dest, "%lu", num)`.
|
@@ -93,7 +100,7 @@ A NULL terminating byte is written.
|
|
93
100
|
|
94
101
|
Returns the number of bytes actually written (excluding the NULL byte).
|
95
102
|
*/
|
96
|
-
inline size_t http_ul2a(char*
|
103
|
+
inline size_t http_ul2a(char *dest, size_t num) {
|
97
104
|
uint8_t digits = 1;
|
98
105
|
size_t tmp = num;
|
99
106
|
while ((tmp /= 10))
|
@@ -110,10 +117,10 @@ inline size_t http_ul2a(char* dest, size_t num) {
|
|
110
117
|
}
|
111
118
|
|
112
119
|
/** Decodes a URL encoded string, no buffer overflow protection. */
|
113
|
-
ssize_t http_decode_url_unsafe(char*
|
120
|
+
ssize_t http_decode_url_unsafe(char *dest, const char *url_data);
|
114
121
|
|
115
122
|
/** Decodes a URL encoded string. */
|
116
|
-
ssize_t http_decode_url(char*
|
123
|
+
ssize_t http_decode_url(char *dest, const char *url_data, size_t length);
|
117
124
|
|
118
125
|
/* *****************************************************************************
|
119
126
|
HTTP versions (they depend on the settings / core data structure)
|
data/ext/iodine/http1.c
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
+
/*
|
2
|
+
copyright: Boaz segev, 2016-2017
|
3
|
+
license: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
1
7
|
#include "http1.h"
|
8
|
+
#include "errno.h"
|
2
9
|
#include "http1_simple_parser.h"
|
3
|
-
#include <string.h>
|
4
|
-
#include <stdio.h>
|
5
10
|
#include <fcntl.h>
|
6
|
-
#include <
|
7
|
-
#include
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <string.h>
|
8
13
|
#include <sys/mman.h>
|
14
|
+
#include <sys/stat.h>
|
9
15
|
|
10
16
|
/* *****************************************************************************
|
11
17
|
HTTP/1.1 data structure
|
@@ -13,23 +19,23 @@ HTTP/1.1 data structure
|
|
13
19
|
|
14
20
|
typedef struct {
|
15
21
|
protocol_s protocol;
|
16
|
-
http_settings_s*
|
22
|
+
http_settings_s *settings;
|
17
23
|
char buffer[HTTP1_MAX_HEADER_SIZE];
|
18
24
|
size_t buffer_pos;
|
19
|
-
void (*on_request)(http_request_s*
|
25
|
+
void (*on_request)(http_request_s *request);
|
20
26
|
http_request_s
|
21
27
|
request; /* MUST be last, as it has memory extensions for the headers*/
|
22
28
|
} http1_protocol_s; /* ~ 8416 bytes for (8 * 1024) buffer size and 64 headers */
|
23
29
|
|
24
|
-
#define HTTP1_PROTOCOL_SIZE
|
30
|
+
#define HTTP1_PROTOCOL_SIZE \
|
25
31
|
(sizeof(http1_protocol_s) + HTTP_REQUEST_SIZE(HTTP1_MAX_HEADER_COUNT))
|
26
32
|
|
27
|
-
char*
|
33
|
+
char *HTTP1 = "http1";
|
28
34
|
|
29
35
|
/* *****************************************************************************
|
30
36
|
HTTP/1.1 callbacks
|
31
37
|
*/
|
32
|
-
static void http1_on_data(intptr_t uuid, http1_protocol_s*
|
38
|
+
static void http1_on_data(intptr_t uuid, http1_protocol_s *protocol);
|
33
39
|
|
34
40
|
/* *****************************************************************************
|
35
41
|
HTTP/1.1 protocol pooling
|
@@ -38,13 +44,13 @@ HTTP/1.1 protocol pooling
|
|
38
44
|
#define HTTP1_POOL_MEMORY_SIZE (HTTP1_PROTOCOL_SIZE * HTTP1_POOL_SIZE)
|
39
45
|
|
40
46
|
struct {
|
41
|
-
void*
|
42
|
-
http1_protocol_s*
|
47
|
+
void *memory;
|
48
|
+
http1_protocol_s *pool;
|
43
49
|
spn_lock_i lock;
|
44
50
|
} http1_pool = {0};
|
45
51
|
|
46
|
-
inline static http1_protocol_s*
|
47
|
-
http1_protocol_s*
|
52
|
+
inline static http1_protocol_s *pool_pop() {
|
53
|
+
http1_protocol_s *prot;
|
48
54
|
spn_lock(&http1_pool.lock);
|
49
55
|
prot = http1_pool.pool;
|
50
56
|
if (prot)
|
@@ -53,7 +59,7 @@ inline static http1_protocol_s* pool_pop() {
|
|
53
59
|
return prot;
|
54
60
|
}
|
55
61
|
|
56
|
-
inline static void pool_push(http1_protocol_s*
|
62
|
+
inline static void pool_push(http1_protocol_s *protocol) {
|
57
63
|
if (protocol == NULL)
|
58
64
|
return;
|
59
65
|
spn_lock(&http1_pool.lock);
|
@@ -83,7 +89,7 @@ static void http1_init(void) {
|
|
83
89
|
atexit(http1_cleanup);
|
84
90
|
|
85
91
|
// initialize pool
|
86
|
-
void*
|
92
|
+
void *pos = http1_pool.memory;
|
87
93
|
while (pos <
|
88
94
|
http1_pool.memory + (HTTP1_POOL_MEMORY_SIZE - HTTP1_PROTOCOL_SIZE)) {
|
89
95
|
pool_push(pos);
|
@@ -94,30 +100,30 @@ static void http1_init(void) {
|
|
94
100
|
}
|
95
101
|
|
96
102
|
/** initializes the library if it wasn't already initialized. */
|
97
|
-
#define validate_mem()
|
98
|
-
{
|
99
|
-
if (http1_pool.memory == NULL)
|
100
|
-
http1_init();
|
103
|
+
#define validate_mem() \
|
104
|
+
{ \
|
105
|
+
if (http1_pool.memory == NULL) \
|
106
|
+
http1_init(); \
|
101
107
|
}
|
102
108
|
|
103
|
-
inline static void http1_free(http1_protocol_s*
|
109
|
+
inline static void http1_free(http1_protocol_s *http) {
|
104
110
|
http_request_clear(&http->request);
|
105
111
|
validate_mem();
|
106
|
-
if (((void*)http) >= http1_pool.memory &&
|
107
|
-
((void*)http) <= (http1_pool.memory + HTTP1_POOL_MEMORY_SIZE)) {
|
112
|
+
if (((void *)http) >= http1_pool.memory &&
|
113
|
+
((void *)http) <= (http1_pool.memory + HTTP1_POOL_MEMORY_SIZE)) {
|
108
114
|
pool_push(http);
|
109
115
|
} else
|
110
116
|
free(http);
|
111
117
|
}
|
112
118
|
|
113
|
-
protocol_s*
|
119
|
+
protocol_s *http1_alloc(intptr_t fd, http_settings_s *settings) {
|
114
120
|
validate_mem();
|
115
121
|
// HTTP/1.1 should send a busy response
|
116
122
|
// if there aren't enough available file descriptors.
|
117
123
|
if (sock_max_capacity() - sock_uuid2fd(fd) <= HTTP_BUSY_UNLESS_HAS_FDS)
|
118
124
|
goto is_busy;
|
119
125
|
// get an http object from the pool
|
120
|
-
http1_protocol_s*
|
126
|
+
http1_protocol_s *http = pool_pop();
|
121
127
|
// of malloc one
|
122
128
|
if (http == NULL)
|
123
129
|
http = malloc(HTTP1_PROTOCOL_SIZE);
|
@@ -133,8 +139,8 @@ protocol_s* http1_alloc(intptr_t fd, http_settings_s* settings) {
|
|
133
139
|
// setup protocol callbacks
|
134
140
|
http->protocol = (protocol_s){
|
135
141
|
.service = HTTP1,
|
136
|
-
.on_data = (void (*)(intptr_t, protocol_s*))http1_on_data,
|
137
|
-
.on_close = (void (*)(protocol_s*))http1_free,
|
142
|
+
.on_data = (void (*)(intptr_t, protocol_s *))http1_on_data,
|
143
|
+
.on_close = (void (*)(protocol_s *))http1_free,
|
138
144
|
};
|
139
145
|
// setup request data
|
140
146
|
http->request = (http_request_s){
|
@@ -147,7 +153,7 @@ protocol_s* http1_alloc(intptr_t fd, http_settings_s* settings) {
|
|
147
153
|
http->on_request = settings->on_request;
|
148
154
|
// set the timeout
|
149
155
|
server_set_timeout(fd, settings->timeout);
|
150
|
-
return (protocol_s*)http;
|
156
|
+
return (protocol_s *)http;
|
151
157
|
|
152
158
|
is_busy:
|
153
159
|
if (settings->public_folder && settings->public_folder_length) {
|
@@ -168,13 +174,12 @@ is_busy:
|
|
168
174
|
int file = open(fname, O_RDONLY);
|
169
175
|
if (file == -1)
|
170
176
|
goto busy_no_file;
|
171
|
-
sock_packet_s*
|
177
|
+
sock_packet_s *packet;
|
172
178
|
packet = sock_checkout_packet();
|
173
|
-
memcpy(packet->buffer,
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
"Content-Length: ",
|
179
|
+
memcpy(packet->buffer, "HTTP/1.1 503 Service Unavailable\r\n"
|
180
|
+
"Content-Type: text/html\r\n"
|
181
|
+
"Connection: close\r\n"
|
182
|
+
"Content-Length: ",
|
178
183
|
94);
|
179
184
|
p_len = 94 + http_ul2a(packet->buffer + 94, file_data.st_size);
|
180
185
|
memcpy(packet->buffer + p_len, "\r\n\r\n", 4);
|
@@ -196,9 +201,8 @@ is_busy:
|
|
196
201
|
return NULL;
|
197
202
|
}
|
198
203
|
busy_no_file:
|
199
|
-
sock_write(fd,
|
200
|
-
|
201
|
-
"13\r\n\r\nServer Busy.",
|
204
|
+
sock_write(fd, "HTTP/1.1 503 Service Unavailable\r\nContent-Length: "
|
205
|
+
"13\r\n\r\nServer Busy.",
|
202
206
|
68);
|
203
207
|
return NULL;
|
204
208
|
}
|
@@ -207,15 +211,15 @@ busy_no_file:
|
|
207
211
|
HTTP/1.1 protocol bare-bones implementation
|
208
212
|
*/
|
209
213
|
|
210
|
-
#define HTTP_BODY_CHUNK_SIZE 3072
|
214
|
+
#define HTTP_BODY_CHUNK_SIZE 3072 // 4096
|
211
215
|
|
212
216
|
/* parse and call callback */
|
213
|
-
static void http1_on_data(intptr_t uuid, http1_protocol_s*
|
217
|
+
static void http1_on_data(intptr_t uuid, http1_protocol_s *protocol) {
|
214
218
|
ssize_t len = 0;
|
215
219
|
ssize_t result;
|
216
220
|
char buff[HTTP_BODY_CHUNK_SIZE];
|
217
|
-
char*
|
218
|
-
http_request_s*
|
221
|
+
char *buffer;
|
222
|
+
http_request_s *request = &protocol->request;
|
219
223
|
for (;;) {
|
220
224
|
// handle requests with no file data
|
221
225
|
if (request->body_file <= 0) {
|
@@ -235,7 +239,7 @@ static void http1_on_data(intptr_t uuid, http1_protocol_s* protocol) {
|
|
235
239
|
result =
|
236
240
|
http1_parse_request_headers(buffer, protocol->buffer_pos, request);
|
237
241
|
// review result
|
238
|
-
if (result >= 0) {
|
242
|
+
if (result >= 0) { // headers comeplete
|
239
243
|
// mark buffer position, for HTTP pipelining
|
240
244
|
protocol->buffer_pos = result;
|
241
245
|
// are we done?
|
@@ -251,10 +255,10 @@ static void http1_on_data(intptr_t uuid, http1_protocol_s* protocol) {
|
|
251
255
|
if (result >= 0) {
|
252
256
|
protocol->buffer_pos += result;
|
253
257
|
goto handle_request;
|
254
|
-
} else if (result == -1)
|
258
|
+
} else if (result == -1) // parser error
|
255
259
|
goto parser_error;
|
256
260
|
goto parse_body;
|
257
|
-
} else if (result == -1)
|
261
|
+
} else if (result == -1) // parser error
|
258
262
|
goto parser_error;
|
259
263
|
// assume incomplete (result == -2), even if wrong, we're right.
|
260
264
|
len = 0;
|
@@ -272,9 +276,9 @@ static void http1_on_data(intptr_t uuid, http1_protocol_s* protocol) {
|
|
272
276
|
// set buffer pos for piplining support
|
273
277
|
protocol->buffer_pos = result;
|
274
278
|
goto handle_request;
|
275
|
-
} else if (result == -1)
|
279
|
+
} else if (result == -1) // parser error
|
276
280
|
goto parser_error;
|
277
|
-
if (len < HTTP_BODY_CHUNK_SIZE)
|
281
|
+
if (len < HTTP_BODY_CHUNK_SIZE) // pause parser for more data
|
278
282
|
return;
|
279
283
|
goto parse_body;
|
280
284
|
}
|
@@ -283,10 +287,10 @@ static void http1_on_data(intptr_t uuid, http1_protocol_s* protocol) {
|
|
283
287
|
// review required headers / data
|
284
288
|
if (request->host == NULL)
|
285
289
|
goto bad_request;
|
286
|
-
http_settings_s*
|
290
|
+
http_settings_s *settings = protocol->settings;
|
287
291
|
// call request callback
|
288
292
|
if (protocol && settings &&
|
289
|
-
(
|
293
|
+
(settings->public_folder == NULL ||
|
290
294
|
http_response_sendfile2(NULL, request, settings->public_folder,
|
291
295
|
settings->public_folder_length, request->path,
|
292
296
|
request->path_len, settings->log_static))) {
|
@@ -308,7 +312,7 @@ static void http1_on_data(intptr_t uuid, http1_protocol_s* protocol) {
|
|
308
312
|
// no routes lead here.
|
309
313
|
fprintf(stderr,
|
310
314
|
"I am lost on a deserted island, no code can reach me here :-)\n");
|
311
|
-
return;
|
315
|
+
return; // How did we get here?
|
312
316
|
parser_error:
|
313
317
|
if (request->headers_count == request->metadata.max_headers)
|
314
318
|
goto too_big;
|
@@ -353,7 +357,7 @@ HTTP/1.1 listenning API implementation
|
|
353
357
|
|
354
358
|
#undef http1_listen
|
355
359
|
|
356
|
-
static void http1_on_init(http_settings_s*
|
360
|
+
static void http1_on_init(http_settings_s *settings) {
|
357
361
|
if (settings->timeout == 0)
|
358
362
|
settings->timeout = 5;
|
359
363
|
if (settings->max_body_size == 0)
|
@@ -362,29 +366,28 @@ static void http1_on_init(http_settings_s* settings) {
|
|
362
366
|
settings->public_folder_length = strlen(settings->public_folder);
|
363
367
|
if (settings->public_folder[0] == '~' &&
|
364
368
|
settings->public_folder[1] == '/' && getenv("HOME")) {
|
365
|
-
char*
|
369
|
+
char *home = getenv("HOME");
|
366
370
|
size_t home_len = strlen(home);
|
367
|
-
char*
|
371
|
+
char *tmp = malloc(settings->public_folder_length + home_len + 1);
|
368
372
|
memcpy(tmp, home, home_len);
|
369
373
|
if (home[home_len - 1] == '/')
|
370
374
|
--home_len;
|
371
375
|
memcpy(tmp + home_len, settings->public_folder + 1,
|
372
|
-
settings->public_folder_length);
|
376
|
+
settings->public_folder_length); // copy also the NULL
|
373
377
|
settings->public_folder = tmp;
|
374
378
|
settings->private_metaflags |= 1;
|
375
379
|
settings->public_folder_length = strlen(settings->public_folder);
|
376
380
|
}
|
377
381
|
}
|
378
382
|
}
|
379
|
-
static void http1_on_finish(http_settings_s*
|
383
|
+
static void http1_on_finish(http_settings_s *settings) {
|
380
384
|
if (settings->private_metaflags & 1)
|
381
|
-
free((void*)settings->public_folder);
|
385
|
+
free((void *)settings->public_folder);
|
382
386
|
if (settings->private_metaflags & 2)
|
383
387
|
free(settings);
|
384
388
|
}
|
385
389
|
|
386
|
-
int http1_listen(const char*
|
387
|
-
const char* address,
|
390
|
+
int http1_listen(const char *port, const char *address,
|
388
391
|
http_settings_s settings) {
|
389
392
|
if (settings.on_request == NULL) {
|
390
393
|
fprintf(
|
@@ -392,11 +395,11 @@ int http1_listen(const char* port,
|
|
392
395
|
"ERROR: http1_listen requires the .on_request parameter to be set\n");
|
393
396
|
exit(11);
|
394
397
|
}
|
395
|
-
http_settings_s*
|
398
|
+
http_settings_s *settings_copy = malloc(sizeof(*settings_copy));
|
396
399
|
*settings_copy = settings;
|
397
400
|
settings_copy->private_metaflags = 2;
|
398
401
|
return server_listen(.port = port, .address = address,
|
399
|
-
.on_start = (void*)http1_on_init,
|
400
|
-
.on_finish = (void*)http1_on_finish,
|
401
|
-
.on_open = (void*)http1_alloc, .udata = settings_copy);
|
402
|
+
.on_start = (void *)http1_on_init,
|
403
|
+
.on_finish = (void *)http1_on_finish,
|
404
|
+
.on_open = (void *)http1_alloc, .udata = settings_copy);
|
402
405
|
}
|