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.

Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/README.md +5 -1
  4. data/ext/iodine/base64.c +3 -3
  5. data/ext/iodine/base64.h +3 -3
  6. data/ext/iodine/bscrypt-common.h +5 -5
  7. data/ext/iodine/bscrypt.h +4 -4
  8. data/ext/iodine/hex.c +11 -10
  9. data/ext/iodine/hex.h +3 -3
  10. data/ext/iodine/http.c +34 -27
  11. data/ext/iodine/http.h +15 -8
  12. data/ext/iodine/http1.c +63 -60
  13. data/ext/iodine/http1.h +10 -5
  14. data/ext/iodine/http1_simple_parser.c +6 -0
  15. data/ext/iodine/http1_simple_parser.h +10 -6
  16. data/ext/iodine/http_request.h +28 -22
  17. data/ext/iodine/http_response.c +22 -7
  18. data/ext/iodine/http_response.h +6 -0
  19. data/ext/iodine/http_response_http1.h +9 -1
  20. data/ext/iodine/iodine_core.c +6 -1
  21. data/ext/iodine/iodine_core.h +13 -6
  22. data/ext/iodine/iodine_http.c +6 -0
  23. data/ext/iodine/iodine_http.h +6 -0
  24. data/ext/iodine/iodine_websocket.c +23 -4
  25. data/ext/iodine/iodine_websocket.h +2 -2
  26. data/ext/iodine/libasync.c +5 -3
  27. data/ext/iodine/libasync.h +8 -8
  28. data/ext/iodine/libreact.c +8 -8
  29. data/ext/iodine/libreact.h +5 -5
  30. data/ext/iodine/libserver.c +2 -2
  31. data/ext/iodine/libserver.h +2 -2
  32. data/ext/iodine/libsock.c +2 -2
  33. data/ext/iodine/libsock.h +3 -3
  34. data/ext/iodine/mempool.h +826 -0
  35. data/ext/iodine/misc.c +14 -14
  36. data/ext/iodine/misc.h +3 -3
  37. data/ext/iodine/random.c +6 -6
  38. data/ext/iodine/random.h +3 -3
  39. data/ext/iodine/rb-call.c +6 -0
  40. data/ext/iodine/rb-call.h +2 -2
  41. data/ext/iodine/rb-libasync.h +5 -3
  42. data/ext/iodine/rb-rack-io.c +15 -3
  43. data/ext/iodine/rb-rack-io.h +5 -2
  44. data/ext/iodine/rb-registry.c +6 -0
  45. data/ext/iodine/rb-registry.h +2 -2
  46. data/ext/iodine/sha1.c +13 -11
  47. data/ext/iodine/sha1.h +3 -3
  48. data/ext/iodine/sha2.c +8 -6
  49. data/ext/iodine/sha2.h +3 -3
  50. data/ext/iodine/siphash.c +9 -2
  51. data/ext/iodine/siphash.h +8 -1
  52. data/ext/iodine/spnlock.h +9 -3
  53. data/ext/iodine/websockets.c +62 -38
  54. data/ext/iodine/websockets.h +6 -0
  55. data/ext/iodine/xor-crypt.c +3 -3
  56. data/ext/iodine/xor-crypt.h +3 -3
  57. data/lib/iodine/version.rb +1 -1
  58. metadata +3 -4
  59. data/ext/iodine/rb-call.c_old +0 -127
  60. 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: 252241f38288180ae589bbe3787c5214a62cef10
4
- data.tar.gz: 39f4936e62585c3f95dc9910de67a82d43093776
3
+ metadata.gz: fc35ddb10525599dcaacd5746e7ad1b6b5798d25
4
+ data.tar.gz: abb7a77d1f0e9e224037aea022d3b58964d24459
5
5
  SHA512:
6
- metadata.gz: c41af300fdffcc3e5721a2c2da23841686b19b1eb6bae2f7c70e3b2bfb954d0182bffa0610846d656b4812ff6abd0b2f678767c908fda305e266cc2b847e2679
7
- data.tar.gz: 1f17f2dd33c1a95ab5e4e5e64afbbea417743b7364fb2826a4d628eea9dabf33f71056a9184892c92c063f2ff6df9e86654fa4199da60cfab017b850fe5baabe
6
+ metadata.gz: 47ae99c46deb8aac630e8b096a0478fb45e1d7aa732f988ca111ebcbc55e13e74fa6c816c27d4f826f89ec0de2ab82b75c0ecf5495a0d560eae54556db6dde87
7
+ data.tar.gz: 810d41cbe10ca2683eb9d6fadbd02cc66df8c6ae55cf1857be6aae4208e1988884f9b24b8240497d435d4ddd9409f7b30f1f0492a7382c0900c870d8d11651da
@@ -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 or processes or threads would initiate a very large number of forks, promoting a resource choke to the system. limited the number of threads (1023) and processes (127).
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 Websocket support means that no automatic process scaling is provided (since Websockets don't share data across processes without your help)... It is important to use `iodine` with the `-w` option and set the number of desired processes (ideally equal to the number of CPU cores).
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
 
@@ -1,7 +1,7 @@
1
1
  /*
2
- (un)copyright: Boaz segev, 2016
3
- License: Public Domain except for any non-public-domain algorithms, which are
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
  */
@@ -1,7 +1,7 @@
1
1
  /*
2
- (un)copyright: Boaz segev, 2016
3
- License: Public Domain except for any non-public-domain algorithms, which are
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
  */
@@ -1,7 +1,7 @@
1
1
  /*
2
- (un)copyright: Boaz segev, 2016
3
- License: Public Domain except for any non-public-domain algorithms, which are
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
 
@@ -1,7 +1,7 @@
1
1
  /*
2
- (un)copyright: Boaz segev, 2016
3
- License: Public Domain except for any non-public-domain algorithms, which are
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"
@@ -1,7 +1,7 @@
1
1
  /*
2
- (un)copyright: Boaz segev, 2016
3
- License: Public Domain except for any non-public-domain algorithms, which are
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') ? ((c)-48) : (((c) >= 'a' && (c) <= 'f') || \
28
- ((c) >= 'A' && (c) <= 'F')) \
29
- ? (((c) | 32) - 87) \
30
- : ({ \
31
- return -1; \
32
- 0; \
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
@@ -1,7 +1,7 @@
1
1
  /*
2
- (un)copyright: Boaz segev, 2016
3
- License: Public Domain except for any non-public-domain algorithms, which are
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
  */
@@ -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* http_gmtime(const time_t* timer, struct tm* tmbuf) {
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, // nonleap year
17
- 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // leap year
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; // tm_year == The number of years since 1900
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) // leap century divisable by 400 => add leap
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) { // leap year
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* DAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
109
- static char* MONTH_NAMES[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
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* GMT_STR = "GMT";
117
+ static const char *GMT_STR = "GMT";
112
118
 
113
- size_t http_date2str(char* target, struct tm* tmbuf) {
114
- char* pos = target;
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') ? ((c)-48) : (((c) >= 'a' && (c) <= 'f') || \
156
- ((c) >= 'A' && (c) <= 'F')) \
157
- ? (((c) | 32) - 87) \
158
- : ({ \
159
- return -1; \
160
- 0; \
161
- }))
162
- ssize_t http_decode_url(char* dest, const char* url_data, size_t length) {
163
- char* pos = dest;
164
- const char* end = url_data + length;
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* dest, const char* url_data) {
183
- char* pos = dest;
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
@@ -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
- #include <time.h>
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* request);
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* public_folder;
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* http_gmtime(const time_t* timer, struct tm* tmbuf);
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* target, struct tm* tmbuf);
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* dest, size_t num) {
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* dest, const char* url_data);
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* dest, const char* url_data, size_t length);
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)
@@ -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 <sys/stat.h>
7
- #include "errno.h"
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* settings;
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* request);
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* HTTP1 = "http1";
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* protocol);
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* memory;
42
- http1_protocol_s* pool;
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* pool_pop() {
47
- http1_protocol_s* prot;
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* protocol) {
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* pos = http1_pool.memory;
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* http) {
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* http1_alloc(intptr_t fd, http_settings_s* settings) {
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* http = pool_pop();
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* packet;
177
+ sock_packet_s *packet;
172
178
  packet = sock_checkout_packet();
173
- memcpy(packet->buffer,
174
- "HTTP/1.1 503 Service Unavailable\r\n"
175
- "Content-Type: text/html\r\n"
176
- "Connection: close\r\n"
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
- "HTTP/1.1 503 Service Unavailable\r\nContent-Length: "
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 // 4096
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* protocol) {
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* buffer;
218
- http_request_s* request = &protocol->request;
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) { // headers comeplete
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) // parser error
258
+ } else if (result == -1) // parser error
255
259
  goto parser_error;
256
260
  goto parse_body;
257
- } else if (result == -1) // parser error
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) // parser error
279
+ } else if (result == -1) // parser error
276
280
  goto parser_error;
277
- if (len < HTTP_BODY_CHUNK_SIZE) // pause parser for more data
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* settings = protocol->settings;
290
+ http_settings_s *settings = protocol->settings;
287
291
  // call request callback
288
292
  if (protocol && settings &&
289
- (protocol->settings->public_folder == NULL ||
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; // How did we get here?
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* settings) {
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* home = getenv("HOME");
369
+ char *home = getenv("HOME");
366
370
  size_t home_len = strlen(home);
367
- char* tmp = malloc(settings->public_folder_length + home_len + 1);
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); // copy also the NULL
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* settings) {
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* port,
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* settings_copy = malloc(sizeof(*settings_copy));
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
  }