iodine 0.4.19 → 0.5.0

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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +22 -0
  4. data/LIMITS.md +19 -9
  5. data/README.md +92 -77
  6. data/SPEC-PubSub-Draft.md +113 -0
  7. data/SPEC-Websocket-Draft.md +127 -143
  8. data/bin/http-hello +0 -1
  9. data/bin/raw-rbhttp +1 -1
  10. data/bin/raw_broadcast +8 -10
  11. data/bin/updated api +2 -2
  12. data/bin/ws-broadcast +2 -4
  13. data/bin/ws-echo +2 -2
  14. data/examples/config.ru +13 -13
  15. data/examples/echo.ru +5 -6
  16. data/examples/hello.ru +2 -3
  17. data/examples/info.md +316 -0
  18. data/examples/pubsub_engine.ru +81 -0
  19. data/examples/redis.ru +9 -9
  20. data/examples/shootout.ru +45 -11
  21. data/ext/iodine/defer.c +194 -297
  22. data/ext/iodine/defer.h +61 -53
  23. data/ext/iodine/evio.c +0 -260
  24. data/ext/iodine/evio.h +50 -22
  25. data/ext/iodine/evio_callbacks.c +26 -0
  26. data/ext/iodine/evio_epoll.c +251 -0
  27. data/ext/iodine/evio_kqueue.c +193 -0
  28. data/ext/iodine/extconf.rb +1 -1
  29. data/ext/iodine/facil.c +1420 -542
  30. data/ext/iodine/facil.h +151 -64
  31. data/ext/iodine/fio_ary.h +418 -0
  32. data/ext/iodine/{base64.c → fio_base64.c} +33 -24
  33. data/ext/iodine/{base64.h → fio_base64.h} +6 -7
  34. data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
  35. data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
  36. data/ext/iodine/fio_hashmap.h +759 -0
  37. data/ext/iodine/fio_json_parser.h +651 -0
  38. data/ext/iodine/fio_llist.h +257 -0
  39. data/ext/iodine/fio_mem.c +672 -0
  40. data/ext/iodine/fio_mem.h +140 -0
  41. data/ext/iodine/fio_random.c +248 -0
  42. data/ext/iodine/{random.h → fio_random.h} +11 -14
  43. data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
  44. data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
  45. data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
  46. data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
  47. data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
  48. data/ext/iodine/fio_siphash.h +18 -0
  49. data/ext/iodine/fio_tmpfile.h +38 -0
  50. data/ext/iodine/fiobj.h +24 -7
  51. data/ext/iodine/fiobj4sock.h +23 -0
  52. data/ext/iodine/fiobj_ary.c +143 -226
  53. data/ext/iodine/fiobj_ary.h +17 -16
  54. data/ext/iodine/fiobj_data.c +1160 -0
  55. data/ext/iodine/fiobj_data.h +164 -0
  56. data/ext/iodine/fiobj_hash.c +298 -406
  57. data/ext/iodine/fiobj_hash.h +101 -54
  58. data/ext/iodine/fiobj_json.c +478 -601
  59. data/ext/iodine/fiobj_json.h +34 -9
  60. data/ext/iodine/fiobj_numbers.c +383 -51
  61. data/ext/iodine/fiobj_numbers.h +87 -11
  62. data/ext/iodine/fiobj_str.c +423 -184
  63. data/ext/iodine/fiobj_str.h +81 -32
  64. data/ext/iodine/fiobject.c +273 -522
  65. data/ext/iodine/fiobject.h +477 -112
  66. data/ext/iodine/http.c +2243 -83
  67. data/ext/iodine/http.h +842 -121
  68. data/ext/iodine/http1.c +810 -385
  69. data/ext/iodine/http1.h +16 -39
  70. data/ext/iodine/http1_parser.c +146 -74
  71. data/ext/iodine/http1_parser.h +15 -4
  72. data/ext/iodine/http_internal.c +1258 -0
  73. data/ext/iodine/http_internal.h +226 -0
  74. data/ext/iodine/http_mime_parser.h +341 -0
  75. data/ext/iodine/iodine.c +86 -68
  76. data/ext/iodine/iodine.h +26 -11
  77. data/ext/iodine/iodine_helpers.c +8 -7
  78. data/ext/iodine/iodine_http.c +487 -324
  79. data/ext/iodine/iodine_json.c +304 -0
  80. data/ext/iodine/iodine_json.h +6 -0
  81. data/ext/iodine/iodine_protocol.c +107 -45
  82. data/ext/iodine/iodine_pubsub.c +526 -225
  83. data/ext/iodine/iodine_pubsub.h +10 -0
  84. data/ext/iodine/iodine_websockets.c +268 -510
  85. data/ext/iodine/iodine_websockets.h +2 -4
  86. data/ext/iodine/pubsub.c +726 -432
  87. data/ext/iodine/pubsub.h +85 -103
  88. data/ext/iodine/rb-call.c +4 -4
  89. data/ext/iodine/rb-defer.c +46 -22
  90. data/ext/iodine/rb-fiobj2rb.h +117 -0
  91. data/ext/iodine/rb-rack-io.c +73 -238
  92. data/ext/iodine/rb-rack-io.h +2 -2
  93. data/ext/iodine/rb-registry.c +35 -93
  94. data/ext/iodine/rb-registry.h +1 -0
  95. data/ext/iodine/redis_engine.c +742 -304
  96. data/ext/iodine/redis_engine.h +42 -39
  97. data/ext/iodine/resp_parser.h +311 -0
  98. data/ext/iodine/sock.c +627 -490
  99. data/ext/iodine/sock.h +345 -297
  100. data/ext/iodine/spnlock.inc +15 -4
  101. data/ext/iodine/websocket_parser.h +16 -20
  102. data/ext/iodine/websockets.c +188 -257
  103. data/ext/iodine/websockets.h +24 -133
  104. data/lib/iodine.rb +52 -7
  105. data/lib/iodine/cli.rb +6 -24
  106. data/lib/iodine/json.rb +40 -0
  107. data/lib/iodine/version.rb +1 -1
  108. data/lib/iodine/websocket.rb +5 -3
  109. data/lib/rack/handler/iodine.rb +58 -13
  110. metadata +38 -48
  111. data/bin/ws-shootout +0 -107
  112. data/examples/broadcast.ru +0 -56
  113. data/ext/iodine/bscrypt-common.h +0 -116
  114. data/ext/iodine/bscrypt.h +0 -49
  115. data/ext/iodine/fio2resp.c +0 -60
  116. data/ext/iodine/fio2resp.h +0 -51
  117. data/ext/iodine/fio_dict.c +0 -446
  118. data/ext/iodine/fio_dict.h +0 -99
  119. data/ext/iodine/fio_hash_table.h +0 -370
  120. data/ext/iodine/fio_list.h +0 -111
  121. data/ext/iodine/fiobj_internal.h +0 -280
  122. data/ext/iodine/fiobj_primitives.c +0 -131
  123. data/ext/iodine/fiobj_primitives.h +0 -55
  124. data/ext/iodine/fiobj_sym.c +0 -135
  125. data/ext/iodine/fiobj_sym.h +0 -60
  126. data/ext/iodine/hex.c +0 -124
  127. data/ext/iodine/hex.h +0 -70
  128. data/ext/iodine/http1_request.c +0 -81
  129. data/ext/iodine/http1_request.h +0 -58
  130. data/ext/iodine/http1_response.c +0 -417
  131. data/ext/iodine/http1_response.h +0 -95
  132. data/ext/iodine/http_request.c +0 -111
  133. data/ext/iodine/http_request.h +0 -102
  134. data/ext/iodine/http_response.c +0 -1703
  135. data/ext/iodine/http_response.h +0 -250
  136. data/ext/iodine/misc.c +0 -182
  137. data/ext/iodine/misc.h +0 -74
  138. data/ext/iodine/random.c +0 -208
  139. data/ext/iodine/redis_connection.c +0 -278
  140. data/ext/iodine/redis_connection.h +0 -86
  141. data/ext/iodine/resp.c +0 -842
  142. data/ext/iodine/resp.h +0 -261
  143. data/ext/iodine/siphash.c +0 -154
  144. data/ext/iodine/siphash.h +0 -22
  145. data/ext/iodine/xor-crypt.c +0 -193
  146. data/ext/iodine/xor-crypt.h +0 -107
@@ -1,81 +0,0 @@
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
- */
7
- #include "http1_request.h"
8
- #include "http1.h"
9
-
10
- #include <string.h>
11
- #include <strings.h>
12
-
13
- /* *****************************************************************************
14
- Initialization
15
- ***************************************************************************** */
16
-
17
- /** Creates / allocates a protocol version's request object. */
18
- http_request_s *http1_request_create(void) {
19
- http1_request_s *req = malloc(sizeof(*req));
20
- req->request.body_file = 0;
21
- http1_request_clear((http_request_s *)req);
22
- return (http_request_s *)req;
23
- }
24
- /** Destroys the request object. */
25
- void http1_request_destroy(http_request_s *request) {
26
- http1_request_clear(request);
27
- free(request);
28
- }
29
- /** Recycle's the request object, clearing it's data. */
30
- void http1_request_clear(http_request_s *request) {
31
- if (request->body_file)
32
- close(request->body_file);
33
- *request = (http_request_s){.http_version = HTTP_V1, .fd = request->fd};
34
- ((http1_request_s *)request)->buffer_pos = 0;
35
- ((http1_request_s *)request)->header_pos = 0;
36
- }
37
- /** Duplicates a request object. */
38
- http_request_s *http1_request_dup(http_request_s *request) {
39
- http1_request_s *req = (http1_request_s *)http1_request_create();
40
- *req = *((http1_request_s *)request);
41
- return (http_request_s *)req;
42
- }
43
-
44
- /* *****************************************************************************
45
- Header Access
46
- ***************************************************************************** */
47
-
48
- /** searches for a header in the request's data store, returning a `header_s`
49
- * structure with all it's data.*/
50
- http_header_s http1_request_header_find(http_request_s *request,
51
- const char *header, size_t header_len) {
52
- for (size_t i = 0; i < request->headers_count; i++) {
53
- if (((http1_request_s *)request)->headers[i].name_len == header_len &&
54
- strncasecmp((char *)header,
55
- (char *)((http1_request_s *)request)->headers[i].name,
56
- header_len) == 0)
57
- return ((http1_request_s *)request)->headers[i];
58
- }
59
- return (http_header_s){.name = NULL};
60
- }
61
- /** Starts itterating the header list, returning the first header. Header
62
- * itteration is NOT thread-safe. */
63
- http_header_s http1_request_header_first(http_request_s *request) {
64
- ((http1_request_s *)request)->header_pos = 0;
65
- if (!request->headers_count)
66
- return (http_header_s){.name = NULL};
67
- return ((http1_request_s *)request)->headers[0];
68
- }
69
- /**
70
- * Continues itterating the header list.
71
- *
72
- * Returns NULL header data if at end of list (header.name == NULL);
73
- *
74
- * Header itteration is NOT thread-safe. */
75
- http_header_s http1_request_header_next(http_request_s *request) {
76
- ((http1_request_s *)request)->header_pos++;
77
- if (((http1_request_s *)request)->header_pos >= request->headers_count)
78
- return (http_header_s){.name = NULL};
79
- return ((http1_request_s *)request)
80
- ->headers[((http1_request_s *)request)->header_pos];
81
- }
@@ -1,58 +0,0 @@
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
- */
7
- #ifndef H_HTTP1_REQUEST_H
8
- #define H_HTTP1_REQUEST_H
9
- #include "http1.h"
10
- #include "http_request.h"
11
-
12
- /* *****************************************************************************
13
- Data Structure
14
- ***************************************************************************** */
15
- typedef struct {
16
- http_request_s request;
17
- size_t buffer_pos;
18
- size_t header_pos;
19
- http_header_s headers[HTTP1_MAX_HEADER_COUNT];
20
- char buffer[HTTP1_MAX_HEADER_SIZE];
21
- } http1_request_s;
22
-
23
- /* *****************************************************************************
24
- Initialization
25
- ***************************************************************************** */
26
-
27
- /** Creates / allocates a protocol version's request object. */
28
- http_request_s *http1_request_create(void);
29
- /** Destroys the request object. */
30
- void http1_request_destroy(http_request_s *);
31
- /** Recycle's the request object, clearing it's data. */
32
- void http1_request_clear(http_request_s *request);
33
- /** Duplicates a request object. */
34
- http_request_s *http1_request_dup(http_request_s *);
35
-
36
- /* *****************************************************************************
37
- Header Access
38
- ***************************************************************************** */
39
-
40
- /** searches for a header in the request's data store, returning a `header_s`
41
- * structure with all it's data.
42
- *
43
- * This doesn't effect header iteration.
44
- */
45
- http_header_s http1_request_header_find(http_request_s *request,
46
- const char *header, size_t header_len);
47
- /** Starts iterating the header list, returning the first header. Header
48
- * iteration is NOT thread-safe. */
49
- http_header_s http1_request_header_first(http_request_s *request);
50
- /**
51
- * Continues iterating the header list.
52
- *
53
- * Returns NULL header data if at end of list (header.name == NULL);
54
- *
55
- * Header itteration is NOT thread-safe. */
56
- http_header_s http1_request_header_next(http_request_s *request);
57
-
58
- #endif /* H_HTTP_REQUEST_H */
@@ -1,417 +0,0 @@
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
- */
7
- #include "spnlock.inc"
8
-
9
- #include "http1_response.h"
10
-
11
- #include <string.h>
12
- #include <strings.h>
13
- /**
14
- The padding for the status line (62 + 2 for the extra \r\n after the headers).
15
- */
16
- #define H1P_HEADER_START 80
17
- #define H1P_OVERFLOW_PADDING 128
18
-
19
- /* *****************************************************************************
20
- Response object & Initialization
21
- ***************************************************************************** */
22
-
23
- typedef struct {
24
- http_response_s response;
25
- size_t buffer_start;
26
- size_t buffer_end;
27
- spn_lock_i lock;
28
- uint8_t use_count;
29
- uint8_t dest_count;
30
- char buffer[HTTP1_MAX_HEADER_SIZE];
31
- } http1_response_s;
32
-
33
- static struct {
34
- spn_lock_i lock;
35
- uint8_t init;
36
- http1_response_s *next;
37
- http1_response_s pool_mem[HTTP1_POOL_SIZE];
38
- } http1_response_pool = {.lock = SPN_LOCK_INIT, .init = 0};
39
-
40
- static inline void http1_response_clear(http1_response_s *rs,
41
- http_request_s *request) {
42
- rs->response = (http_response_s){
43
- .http_version = HTTP_V1,
44
- .request = request,
45
- .fd = request->fd,
46
- .status = 200,
47
- .date = facil_last_tick(),
48
- .should_close = (request->connection && request->connection_len == 5) ||
49
- (!request->connection && request->version &&
50
- (request->version_len < 8 ||
51
- (request->version[request->version_len - 1] == '0' &&
52
- request->version[request->version_len - 3] == '1')))};
53
- rs->buffer_end = rs->buffer_start = H1P_HEADER_START;
54
- rs->use_count = 1;
55
- rs->lock = SPN_LOCK_INIT;
56
- }
57
- /** Creates / allocates a protocol version's response object. */
58
- http_response_s *http1_response_create(http_request_s *request) {
59
- http1_response_s *rs;
60
- spn_lock(&http1_response_pool.lock);
61
- if (!http1_response_pool.next)
62
- goto use_malloc;
63
- rs = http1_response_pool.next;
64
- http1_response_pool.next = (void *)rs->response.request;
65
- spn_unlock(&http1_response_pool.lock);
66
- http1_response_clear(rs, request);
67
- return (http_response_s *)rs;
68
- use_malloc:
69
- if (http1_response_pool.init == 0)
70
- goto initialize;
71
- spn_unlock(&http1_response_pool.lock);
72
- rs = malloc(sizeof(*rs));
73
- http1_response_clear(rs, request);
74
- return (http_response_s *)rs;
75
- initialize:
76
- http1_response_pool.init = 1;
77
- for (size_t i = 1; i < (HTTP1_POOL_SIZE - 1); i++) {
78
- http1_response_pool.pool_mem[i].response.request =
79
- (void *)(http1_response_pool.pool_mem + (i + 1));
80
- }
81
- http1_response_pool.pool_mem[HTTP1_POOL_SIZE - 1].response.request = NULL;
82
- http1_response_pool.next = http1_response_pool.pool_mem + 1;
83
- spn_unlock(&http1_response_pool.lock);
84
- http1_response_clear(http1_response_pool.pool_mem, request);
85
- return (http_response_s *)http1_response_pool.pool_mem;
86
- }
87
-
88
- static void http1_response_deferred_destroy(void *rs_, void *ignr) {
89
- (void)(ignr);
90
- http1_response_s *rs = rs_;
91
- if (spn_trylock(&rs->lock)) {
92
- defer(http1_response_deferred_destroy, rs, NULL);
93
- return;
94
- }
95
- rs->use_count -= 1;
96
- if (rs->use_count) {
97
- spn_unlock(&rs->lock);
98
- return;
99
- }
100
-
101
- if (rs->response.request_dupped)
102
- http_request_destroy(rs->response.request);
103
-
104
- if ((uintptr_t)rs < (uintptr_t)http1_response_pool.pool_mem ||
105
- (uintptr_t)rs >
106
- (uintptr_t)(http1_response_pool.pool_mem + (HTTP1_POOL_SIZE - 1)))
107
- goto use_free;
108
- spn_lock(&http1_response_pool.lock);
109
- rs->response.request = (void *)http1_response_pool.next;
110
- http1_response_pool.next = (void *)rs;
111
- spn_unlock(&http1_response_pool.lock);
112
- return;
113
- use_free:
114
- free(rs);
115
- return;
116
- }
117
-
118
- /** Destroys the response object. No data is sent.*/
119
- void http1_response_destroy(http_response_s *rs) {
120
- ((http1_response_s *)rs)->dest_count++;
121
- http1_response_deferred_destroy(rs, NULL);
122
- }
123
-
124
- /* *****************************************************************************
125
- Writing and Finishing Helpers + `http1_response_finish`
126
- ***************************************************************************** */
127
-
128
- static int h1p_protected_copy(http1_response_s *rs, void *buff, size_t len) {
129
- if (len + rs->buffer_end >= HTTP1_MAX_HEADER_SIZE - H1P_OVERFLOW_PADDING)
130
- return -1;
131
- memcpy(rs->buffer + rs->buffer_end, buff, len);
132
- rs->buffer_end += len;
133
- return 0;
134
- }
135
-
136
- static void http1_response_finalize_headers(http1_response_s *rs) {
137
- if (rs->response.headers_sent)
138
- return;
139
- rs->response.headers_sent = 1;
140
- const char *status = http_response_status_str(rs->response.status);
141
- if (!status) {
142
- rs->response.status = 500;
143
- status = http_response_status_str(rs->response.status);
144
- }
145
-
146
- /* write the content length header, unless forced not to (<0) */
147
- if (rs->response.content_length_written == 0 &&
148
- !(rs->response.content_length < 0) && rs->response.status >= 200 &&
149
- rs->response.status != 204 && rs->response.status != 304) {
150
- h1p_protected_copy(rs, "Content-Length: ", 16);
151
- rs->buffer_end +=
152
- http_ul2a(rs->buffer + rs->buffer_end, rs->response.content_length);
153
- /* write the header seperator (`\r\n`) */
154
- rs->buffer[rs->buffer_end++] = '\r';
155
- rs->buffer[rs->buffer_end++] = '\n';
156
- }
157
- /* write the date, if missing */
158
- if (!rs->response.date_written) {
159
- if (!rs->response.last_modified)
160
- rs->response.last_modified = rs->response.date;
161
- else if (rs->response.date < rs->response.last_modified)
162
- rs->response.date = rs->response.last_modified;
163
- /* date header */
164
- h1p_protected_copy(rs, "Date: ", 6);
165
- rs->buffer_end +=
166
- http_time2str(rs->buffer + rs->buffer_end, rs->response.date);
167
- rs->buffer[rs->buffer_end++] = '\r';
168
- rs->buffer[rs->buffer_end++] = '\n';
169
- /* last-modified header */
170
- h1p_protected_copy(rs, "Last-Modified: ", 15);
171
- rs->buffer_end +=
172
- http_time2str(rs->buffer + rs->buffer_end, rs->response.last_modified);
173
- rs->buffer[rs->buffer_end++] = '\r';
174
- rs->buffer[rs->buffer_end++] = '\n';
175
- }
176
- /* write the keep-alive (connection) header, if missing */
177
- if (!rs->response.connection_written) {
178
- if (rs->response.should_close) {
179
- h1p_protected_copy(rs, "Connection: close\r\n", 19);
180
- } else {
181
- // h1p_protected_copy(rs,
182
- // "Connection:keep-alive\r\n"
183
- // "Keep-Alive:timeout=2\r\n",
184
- // 45);
185
- h1p_protected_copy(rs, "Connection: keep-alive\r\n", 24);
186
- }
187
- }
188
- /* write the headers completion marker (empty line - `\r\n`) */
189
- rs->buffer[rs->buffer_end++] = '\r';
190
- rs->buffer[rs->buffer_end++] = '\n';
191
-
192
- /* write the status string is "HTTP/1.1 xxx <...>\r\n" length == 15 +
193
- * strlen(status) */
194
-
195
- size_t tmp = strlen(status);
196
- rs->buffer_start = H1P_HEADER_START - (15 + tmp);
197
- memcpy(rs->buffer + rs->buffer_start, "HTTP/1.1 ### ", 13);
198
- memcpy(rs->buffer + rs->buffer_start + 13, status, tmp);
199
- rs->buffer[H1P_HEADER_START - 1] = '\n';
200
- rs->buffer[H1P_HEADER_START - 2] = '\r';
201
- tmp = rs->response.status / 10;
202
- *(rs->buffer + rs->buffer_start + 9) = '0' + (tmp / 10);
203
- *(rs->buffer + rs->buffer_start + 11) =
204
- '0' + (rs->response.status - (10 * tmp));
205
- *(rs->buffer + rs->buffer_start + 10) = '0' + (tmp - (10 * (tmp / 10)));
206
- }
207
-
208
- int http1_response_send_headers(http1_response_s *rs) {
209
- if (!rs->buffer_end)
210
- return 0;
211
- http1_response_finalize_headers(rs);
212
- spn_lock(&rs->lock);
213
- rs->use_count++;
214
- spn_unlock(&rs->lock);
215
- if (sock_write2(.uuid = rs->response.fd, .buffer = rs,
216
- .offset = ((uintptr_t)(rs->buffer + rs->buffer_start) -
217
- (uintptr_t)rs),
218
- .length = rs->buffer_end - rs->buffer_start, .move = 1,
219
- .dealloc = (void (*)(void *))http1_response_destroy) < 0)
220
- return -1;
221
- rs->buffer_end = 0;
222
- return 0;
223
- }
224
-
225
- /** Sends the data and destroys the response object.*/
226
- void http1_response_finish(http_response_s *rs) {
227
- if (!rs->headers_sent)
228
- http1_response_send_headers((http1_response_s *)rs);
229
- if (rs->should_close)
230
- sock_close(rs->fd);
231
- http1_response_deferred_destroy(rs, NULL);
232
- }
233
-
234
- /* *****************************************************************************
235
- Writing data to the response object
236
- ***************************************************************************** */
237
-
238
- /**
239
- Writes a header to the response. This function writes only the requested
240
- number of bytes from the header name and the requested number of bytes from
241
- the header value. It can be used even when the header name and value don't
242
- contain NULL terminating bytes by passing the `.name_len` or `.value_len` data
243
- in the `http_headers_s` structure.
244
-
245
- If the header buffer is full or the headers were already sent (new headers
246
- cannot be sent), the function will return -1.
247
-
248
- On success, the function returns 0.
249
- */
250
- int http1_response_write_header_fn(http_response_s *rs_, http_header_s header) {
251
- http1_response_s *rs = (http1_response_s *)rs_;
252
- if (rs->buffer_end + header.name_len + header.value_len >=
253
- HTTP1_MAX_HEADER_SIZE - H1P_OVERFLOW_PADDING - 5)
254
- return -1;
255
- size_t org_pos = rs->buffer_end;
256
- if (h1p_protected_copy(rs, (void *)header.name, header.name_len))
257
- goto error;
258
- rs->buffer[rs->buffer_end++] = ':';
259
- rs->buffer[rs->buffer_end++] = ' ';
260
- if (h1p_protected_copy(rs, (void *)header.value, header.value_len))
261
- goto error;
262
- rs->buffer[rs->buffer_end++] = '\r';
263
- rs->buffer[rs->buffer_end++] = '\n';
264
- return 0;
265
- error:
266
- rs->buffer_end = org_pos;
267
- return -1;
268
- }
269
-
270
- /**
271
- Set / Delete a cookie using this helper function.
272
-
273
- This function writes a cookie header to the response. Only the requested
274
- number of bytes from the cookie value and name are written (if none are
275
- provided, a terminating NULL byte is assumed).
276
-
277
- Both the name and the value of the cookie are checked for validity (legal
278
- characters), but other properties aren't reviewed (domain/path) - please make
279
- sure to use only valid data, as HTTP imposes restrictions on these things.
280
-
281
- If the header buffer is full or the headers were already sent (new headers
282
- cannot be sent), the function will return -1.
283
-
284
- On success, the function returns 0.
285
- */
286
- int http1_response_set_cookie(http_response_s *rs, http_cookie_s cookie) {
287
- http1_response_s *const rs1 = (http1_response_s *)rs;
288
- if (rs->headers_sent ||
289
- (rs1->buffer_end + cookie.value_len + cookie.name_len >=
290
- (HTTP1_MAX_HEADER_SIZE - H1P_OVERFLOW_PADDING)))
291
- return -1; /* must have a cookie name. */
292
- size_t org_pos = rs1->buffer_end;
293
-
294
- /* write the header's name to the buffer */
295
- if (h1p_protected_copy(rs1, "Set-Cookie: ", 12))
296
- goto error;
297
- if (h1p_protected_copy(rs1, cookie.name, cookie.name_len))
298
- goto error;
299
-
300
- /* seperate name from value */
301
- rs1->buffer[rs1->buffer_end++] = '=';
302
- /* write the cookie value, if any */
303
- if (cookie.value) {
304
- if (h1p_protected_copy(rs1, cookie.value, cookie.value_len))
305
- goto error;
306
- } else {
307
- cookie.max_age = -1;
308
- }
309
- /* complete value data */
310
- rs1->buffer[rs1->buffer_end++] = ';';
311
- if (cookie.max_age) {
312
- rs1->buffer_end +=
313
- sprintf(rs1->buffer + rs1->buffer_end, "Max-Age=%d;", cookie.max_age);
314
- }
315
- if (cookie.domain) {
316
- memcpy(rs1->buffer + rs1->buffer_end, "domain=", 7);
317
- rs1->buffer_end += 7;
318
- if (h1p_protected_copy(rs1, cookie.domain, cookie.domain_len))
319
- return -1;
320
- rs1->buffer[rs1->buffer_end++] = ';';
321
- }
322
- if (cookie.path) {
323
- memcpy(rs1->buffer + rs1->buffer_end, "path=", 5);
324
- rs1->buffer_end += 5;
325
- if (h1p_protected_copy(rs1, cookie.path, cookie.path_len))
326
- return -1;
327
- rs1->buffer[rs1->buffer_end++] = ';';
328
- }
329
- if (cookie.http_only) {
330
- memcpy(rs1->buffer + rs1->buffer_end, "HttpOnly;", 9);
331
- rs1->buffer_end += 9;
332
- }
333
- if (cookie.secure) {
334
- memcpy(rs1->buffer + rs1->buffer_end, "secure;", 7);
335
- rs1->buffer_end += 7;
336
- }
337
- rs1->buffer[rs1->buffer_end++] = '\r';
338
- rs1->buffer[rs1->buffer_end++] = '\n';
339
- return 0;
340
-
341
- error:
342
- rs1->buffer_end = org_pos;
343
- return -1;
344
- }
345
-
346
- /**
347
- Sends the headers (if they weren't previously sent) and writes the data to the
348
- underlying socket.
349
-
350
- The body will be copied to the server's outgoing buffer.
351
-
352
- If the connection was already closed, the function will return -1. On success,
353
- the function returns 0.
354
- */
355
- int http1_response_write_body(http_response_s *rs, const char *body,
356
- size_t length) {
357
- if (!sock_isvalid(rs->fd))
358
- return -1;
359
- http1_response_s *rs1 = (http1_response_s *)rs;
360
- size_t tmp;
361
- if (!rs->headers_sent) {
362
- http1_response_finalize_headers(rs1);
363
- tmp = (length + rs1->buffer_end >= HTTP1_MAX_HEADER_SIZE)
364
- ? HTTP1_MAX_HEADER_SIZE - rs1->buffer_end
365
- : length;
366
- memcpy(rs1->buffer + rs1->buffer_end, body, tmp);
367
- rs1->buffer_end += tmp;
368
- http1_response_send_headers(rs1);
369
- length -= tmp;
370
- body += tmp;
371
- }
372
- if (length)
373
- return (sock_write(rs->fd, body, length) >= 0);
374
- return 0;
375
- }
376
-
377
- /**
378
- Sends the headers (if they weren't previously sent) and writes the data to the
379
- underlying socket.
380
-
381
- The server's outgoing buffer will take ownership of the file and close it
382
- using `close` once the data was sent.
383
-
384
- If the connection was already closed, the function will return -1. On success,
385
- the function returns 0.
386
- */
387
- int http1_response_sendfile(http_response_s *rs, int source_fd, off_t offset,
388
- size_t length) {
389
- if (!sock_isvalid(rs->fd) || !length) {
390
- close(source_fd);
391
- return -1;
392
- }
393
- http1_response_s *rs1 = (http1_response_s *)rs;
394
- ssize_t tmp;
395
- if (!rs->headers_sent) {
396
- http1_response_finalize_headers(rs1);
397
- tmp = (length + rs1->buffer_end >= HTTP1_MAX_HEADER_SIZE)
398
- ? HTTP1_MAX_HEADER_SIZE - rs1->buffer_end
399
- : length;
400
- tmp = pread(source_fd, rs1->buffer + rs1->buffer_end, tmp, offset);
401
- if (tmp <= 0) {
402
- close(source_fd);
403
- return -1;
404
- }
405
- rs1->buffer_end += tmp;
406
- http1_response_send_headers(rs1);
407
- length -= tmp;
408
- offset += tmp;
409
- }
410
- if (length)
411
- return (sock_write2(.uuid = rs->fd, .data_fd = source_fd, .length = length,
412
- .offset = offset, .is_fd = 1, .move = 1) >= 0);
413
- else
414
- close(source_fd);
415
-
416
- return 0;
417
- }