iodine 0.2.17 → 0.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +36 -3
  4. data/bin/config.ru +23 -2
  5. data/bin/http-hello +1 -1
  6. data/bin/ws-shootout +5 -0
  7. data/ext/iodine/defer.c +468 -0
  8. data/ext/iodine/defer.h +105 -0
  9. data/ext/iodine/evio.c +263 -0
  10. data/ext/iodine/evio.h +133 -0
  11. data/ext/iodine/extconf.rb +2 -1
  12. data/ext/iodine/facil.c +958 -0
  13. data/ext/iodine/facil.h +423 -0
  14. data/ext/iodine/http.c +90 -0
  15. data/ext/iodine/http.h +50 -12
  16. data/ext/iodine/http1.c +200 -267
  17. data/ext/iodine/http1.h +17 -26
  18. data/ext/iodine/http1_request.c +81 -0
  19. data/ext/iodine/http1_request.h +58 -0
  20. data/ext/iodine/http1_response.c +403 -0
  21. data/ext/iodine/http1_response.h +90 -0
  22. data/ext/iodine/http1_simple_parser.c +124 -108
  23. data/ext/iodine/http1_simple_parser.h +8 -3
  24. data/ext/iodine/http_request.c +104 -0
  25. data/ext/iodine/http_request.h +58 -102
  26. data/ext/iodine/http_response.c +212 -208
  27. data/ext/iodine/http_response.h +89 -252
  28. data/ext/iodine/iodine_core.c +57 -46
  29. data/ext/iodine/iodine_core.h +3 -1
  30. data/ext/iodine/iodine_http.c +105 -81
  31. data/ext/iodine/iodine_websocket.c +17 -13
  32. data/ext/iodine/iodine_websocket.h +1 -0
  33. data/ext/iodine/rb-call.c +9 -7
  34. data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
  35. data/ext/iodine/rb-rack-io.c +12 -6
  36. data/ext/iodine/rb-rack-io.h +1 -1
  37. data/ext/iodine/rb-registry.c +5 -2
  38. data/ext/iodine/sock.c +1159 -0
  39. data/ext/iodine/{libsock.h → sock.h} +138 -142
  40. data/ext/iodine/spnlock.inc +77 -0
  41. data/ext/iodine/websockets.c +101 -112
  42. data/ext/iodine/websockets.h +38 -19
  43. data/iodine.gemspec +3 -3
  44. data/lib/iodine/version.rb +1 -1
  45. data/lib/rack/handler/iodine.rb +6 -6
  46. metadata +23 -19
  47. data/ext/iodine/http_response_http1.h +0 -382
  48. data/ext/iodine/libasync.c +0 -570
  49. data/ext/iodine/libasync.h +0 -122
  50. data/ext/iodine/libreact.c +0 -350
  51. data/ext/iodine/libreact.h +0 -244
  52. data/ext/iodine/libserver.c +0 -957
  53. data/ext/iodine/libserver.h +0 -481
  54. data/ext/iodine/libsock.c +0 -1025
  55. data/ext/iodine/spnlock.h +0 -243
@@ -31,8 +31,8 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.required_ruby_version = '>= 2.2.2' # for Rack
33
33
 
34
- spec.add_dependency 'rack'
35
- spec.add_dependency 'rake-compiler'
34
+ spec.add_dependency 'rack', '>= 2'
35
+ spec.add_dependency 'rake-compiler', '>= 1'
36
36
 
37
37
  spec.requirements << 'A Unix based system: Linux / macOS / BSD.'
38
38
  spec.requirements << 'An updated C compiler.'
@@ -41,7 +41,7 @@ Gem::Specification.new do |spec|
41
41
 
42
42
  spec.add_development_dependency 'bundler', '~> 1.10'
43
43
  spec.add_development_dependency 'rake', '~> 12.0'
44
- spec.add_development_dependency 'minitest'
44
+ spec.add_development_dependency 'minitest', '>=1'
45
45
 
46
46
  # spec.post_install_message = "** WARNING!\n" \
47
47
  # "Iodine 0.2.0 is NOT an upgrade - it's a total rewrite, it's written in C specifically for Ruby MRI.\n\n" \
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.2.17'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
@@ -86,7 +86,7 @@ module Iodine
86
86
  @port
87
87
  end
88
88
  @port = ARGV[ARGV.index('-p') + 1] if ARGV.index('-p')
89
- @port ||= 3000
89
+ @port ||= 3000.to_s
90
90
 
91
91
  # get/set the HTTP socket binding address. Defaults to `nil` (usually best).
92
92
  def self.address=(val)
@@ -112,15 +112,15 @@ module Iodine
112
112
  else
113
113
  @app = app
114
114
  end
115
- @port = options[:Port] if options[:Port]
116
- @port = options[:Address] if options[:Address]
115
+ @port = options[:Port].to_s if options[:Port]
116
+ @port = options[:Address].to_s if options[:Address]
117
117
  # provide Websocket features using Rack::Websocket
118
- Rack.send :remove_const, :Websocket if defined?(Rack::Websocket)
119
- Rack.const_set :Websocket, ::Iodine::Websocket
118
+ # Rack.send :remove_const, :Websocket if defined?(Rack::Websocket)
119
+ # Rack.const_set :Websocket, ::Iodine::Websocket
120
120
  # start Iodine
121
121
  Iodine.start
122
122
  # remove the Websocket features from Rack::Websocket
123
- Rack.send :remove_const, :Websocket
123
+ # Rack.send :remove_const, :Websocket
124
124
  true
125
125
  end
126
126
  IODINE_RACK_LOADED = true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.17
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-16 00:00:00.000000000 Z
11
+ date: 2017-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake-compiler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '1'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '1'
83
83
  description: " Iodine - leveraging C for Ruby servers."
84
84
  email:
85
85
  - Boaz@2be.co.il
@@ -121,40 +121,42 @@ files:
121
121
  - ext/iodine/base64.h
122
122
  - ext/iodine/bscrypt-common.h
123
123
  - ext/iodine/bscrypt.h
124
+ - ext/iodine/defer.c
125
+ - ext/iodine/defer.h
126
+ - ext/iodine/evio.c
127
+ - ext/iodine/evio.h
124
128
  - ext/iodine/extconf.rb
129
+ - ext/iodine/facil.c
130
+ - ext/iodine/facil.h
125
131
  - ext/iodine/hex.c
126
132
  - ext/iodine/hex.h
127
133
  - ext/iodine/http.c
128
134
  - ext/iodine/http.h
129
135
  - ext/iodine/http1.c
130
136
  - ext/iodine/http1.h
137
+ - ext/iodine/http1_request.c
138
+ - ext/iodine/http1_request.h
139
+ - ext/iodine/http1_response.c
140
+ - ext/iodine/http1_response.h
131
141
  - ext/iodine/http1_simple_parser.c
132
142
  - ext/iodine/http1_simple_parser.h
143
+ - ext/iodine/http_request.c
133
144
  - ext/iodine/http_request.h
134
145
  - ext/iodine/http_response.c
135
146
  - ext/iodine/http_response.h
136
- - ext/iodine/http_response_http1.h
137
147
  - ext/iodine/iodine_core.c
138
148
  - ext/iodine/iodine_core.h
139
149
  - ext/iodine/iodine_http.c
140
150
  - ext/iodine/iodine_http.h
141
151
  - ext/iodine/iodine_websocket.c
142
152
  - ext/iodine/iodine_websocket.h
143
- - ext/iodine/libasync.c
144
- - ext/iodine/libasync.h
145
- - ext/iodine/libreact.c
146
- - ext/iodine/libreact.h
147
- - ext/iodine/libserver.c
148
- - ext/iodine/libserver.h
149
- - ext/iodine/libsock.c
150
- - ext/iodine/libsock.h
151
153
  - ext/iodine/misc.c
152
154
  - ext/iodine/misc.h
153
155
  - ext/iodine/random.c
154
156
  - ext/iodine/random.h
155
157
  - ext/iodine/rb-call.c
156
158
  - ext/iodine/rb-call.h
157
- - ext/iodine/rb-libasync.h
159
+ - ext/iodine/rb-defer.c
158
160
  - ext/iodine/rb-rack-io.c
159
161
  - ext/iodine/rb-rack-io.h
160
162
  - ext/iodine/rb-registry.c
@@ -165,7 +167,9 @@ files:
165
167
  - ext/iodine/sha2.h
166
168
  - ext/iodine/siphash.c
167
169
  - ext/iodine/siphash.h
168
- - ext/iodine/spnlock.h
170
+ - ext/iodine/sock.c
171
+ - ext/iodine/sock.h
172
+ - ext/iodine/spnlock.inc
169
173
  - ext/iodine/websockets.c
170
174
  - ext/iodine/websockets.h
171
175
  - ext/iodine/xor-crypt.c
@@ -1,382 +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 HTTP1_RESPONSE_FORMATTER
8
- #define HTTP1_RESPONSE_FORMATTER
9
-
10
- // clang-format off
11
- #include "libsock.h"
12
- #include "http_response.h"
13
- // clang-format on
14
-
15
- #ifndef UNUSED_FUNC
16
- #define UNUSED_FUNC __attribute__((unused))
17
- #endif
18
-
19
- /* *****************************************************************************
20
- Helpers
21
- ***************************************************************************** */
22
-
23
- /**
24
- The padding for the status line (62 + 2 for the extra \r\n after the headers).
25
- */
26
- #define H1P_HEADER_START 80
27
- #define H1P_OVERFLOW_PADDING 512
28
-
29
- /** checks for overflow */
30
- #define overflowing(response) \
31
- (((response)->metadata.headers_pos - \
32
- (char *)((response)->metadata.packet->buffer)) >= \
33
- (BUFFER_PACKET_SIZE - H1P_OVERFLOW_PADDING))
34
-
35
- #define HEADERS_FINISHED(response) \
36
- ((response)->metadata.packet == NULL || (response)->metadata.headers_sent)
37
-
38
- #define invalid_cookie_char(c) \
39
- ((c) < '!' || (c) > '~' || (c) == '=' || (c) == ' ' || (c) == ',' || \
40
- (c) == ';')
41
-
42
- #define h1p_validate_hpos(response) \
43
- { \
44
- if ((response)->metadata.headers_pos == 0) { \
45
- (response)->metadata.headers_pos = \
46
- (response)->metadata.packet->buffer + H1P_HEADER_START; \
47
- } \
48
- }
49
- static inline int h1p_protected_copy(http_response_s *response,
50
- const char *data, size_t data_len) {
51
- if (data_len > 0 && data_len < H1P_OVERFLOW_PADDING) {
52
- memcpy(response->metadata.headers_pos, data, data_len);
53
- response->metadata.headers_pos += data_len;
54
- } else {
55
- while (*data) {
56
- if (overflowing(response))
57
- return -1;
58
- *(response->metadata.headers_pos++) = *(data++);
59
- }
60
- }
61
- return overflowing(response);
62
- }
63
-
64
- /* this function assume the padding in `h1p_protected_copy` saved enough room
65
- * for the data to be safely written.*/
66
- UNUSED_FUNC static inline sock_packet_s *
67
- h1p_finalize_headers(http_response_s *response) {
68
- if (HEADERS_FINISHED(response))
69
- return NULL;
70
- h1p_validate_hpos(response);
71
-
72
- sock_packet_s *headers = response->metadata.packet;
73
- response->metadata.packet = NULL;
74
- const char *status = http_response_status_str(response->status);
75
- if (!status) {
76
- response->status = 500;
77
- status = http_response_status_str(response->status);
78
- }
79
-
80
- /* write the content length header, unless forced not to (<0) */
81
- if (response->metadata.content_length_written == 0 &&
82
- !(response->content_length < 0) && response->status >= 200 &&
83
- response->status != 204 && response->status != 304) {
84
- h1p_protected_copy(response, "Content-Length:", 15);
85
- response->metadata.headers_pos +=
86
- http_ul2a(response->metadata.headers_pos, response->content_length);
87
- /* write the header seperator (`\r\n`) */
88
- *(response->metadata.headers_pos++) = '\r';
89
- *(response->metadata.headers_pos++) = '\n';
90
- }
91
- /* write the date, if missing */
92
- if (!response->metadata.date_written) {
93
- if (response->date < response->last_modified)
94
- response->date = response->last_modified;
95
- struct tm t;
96
- /* date header */
97
- http_gmtime(&response->date, &t);
98
- h1p_protected_copy(response, "Date:", 5);
99
- response->metadata.headers_pos +=
100
- http_date2str(response->metadata.headers_pos, &t);
101
- *(response->metadata.headers_pos++) = '\r';
102
- *(response->metadata.headers_pos++) = '\n';
103
- /* last-modified header */
104
- http_gmtime(&response->last_modified, &t);
105
- h1p_protected_copy(response, "Last-Modified:", 14);
106
- response->metadata.headers_pos +=
107
- http_date2str(response->metadata.headers_pos, &t);
108
- *(response->metadata.headers_pos++) = '\r';
109
- *(response->metadata.headers_pos++) = '\n';
110
- }
111
- /* write the keep-alive (connection) header, if missing */
112
- if (!response->metadata.connection_written) {
113
- if (response->metadata.should_close) {
114
- h1p_protected_copy(response, "Connection:close\r\n", 18);
115
- } else {
116
- h1p_protected_copy(response, "Connection:keep-alive\r\n"
117
- "Keep-Alive:timeout=2\r\n",
118
- 45);
119
- }
120
- }
121
- /* write the headers completion marker (empty line - `\r\n`) */
122
- *(response->metadata.headers_pos++) = '\r';
123
- *(response->metadata.headers_pos++) = '\n';
124
-
125
- /* write the status string is "HTTP/1.1 xxx <...>\r\n" length == 15 +
126
- * strlen(status) */
127
-
128
- size_t tmp = strlen(status);
129
- int start = H1P_HEADER_START - (15 + tmp);
130
- memcpy(headers->buffer + start, "HTTP/1.1 ### ", 13);
131
- memcpy(headers->buffer + start + 13, status, tmp);
132
- ((char *)headers->buffer)[H1P_HEADER_START - 1] = '\n';
133
- ((char *)headers->buffer)[H1P_HEADER_START - 2] = '\r';
134
- tmp = response->status / 10;
135
- *((char *)headers->buffer + start + 11) =
136
- '0' + (response->status - (10 * tmp));
137
- *((char *)headers->buffer + start + 10) = '0' + (tmp - (10 * (tmp / 10)));
138
- *((char *)headers->buffer + start + 9) = '0' + (response->status / 100);
139
-
140
- headers->buffer = (char *)headers->buffer + start;
141
- headers->length = response->metadata.headers_pos - (char *)headers->buffer;
142
- return headers;
143
- }
144
-
145
- static int h1p_send_headers(http_response_s *response, sock_packet_s *packet) {
146
- if (packet == NULL)
147
- return -1;
148
- /* mark headers as sent */
149
- response->metadata.headers_sent = 1;
150
- response->metadata.packet = NULL;
151
- response->metadata.headers_pos = (char *)packet->length;
152
- /* write data to network */
153
- return sock_send_packet(response->metadata.fd, packet);
154
- };
155
-
156
- /* *****************************************************************************
157
- Implementation
158
- ***************************************************************************** */
159
-
160
- UNUSED_FUNC static inline int h1p_response_write_header(http_response_s *response,
161
- http_headers_s header) {
162
- if (HEADERS_FINISHED(response) || header.name == NULL)
163
- return -1;
164
-
165
- h1p_validate_hpos(response);
166
-
167
- if (h1p_protected_copy(response, header.name, header.name_length))
168
- return -1;
169
- *(response->metadata.headers_pos++) = ':';
170
- /* *(response->metadata.headers_pos++) = ' '; -- better leave out */
171
- if (header.value != NULL &&
172
- h1p_protected_copy(response, header.value, header.value_length))
173
- return -1;
174
- *(response->metadata.headers_pos++) = '\r';
175
- *(response->metadata.headers_pos++) = '\n';
176
- return 0;
177
- }
178
-
179
- /**
180
- Set / Delete a cookie using this helper function.
181
- */
182
- UNUSED_FUNC static int h1p_response_set_cookie(http_response_s *response,
183
- http_cookie_s cookie) {
184
- if (HEADERS_FINISHED(response) || cookie.name == NULL ||
185
- overflowing(response))
186
- return -1; /* must have a cookie name. */
187
- h1p_validate_hpos(response);
188
-
189
- /* write the header's name to the buffer */
190
- if (h1p_protected_copy(response, "Set-Cookie:", 11))
191
- return -1;
192
-
193
- /* we won't use h1p_protected_copy because we'll be testing the name and value
194
- * for illegal characters. */
195
-
196
- /* write the cookie name */
197
- if (cookie.name_len && cookie.name_len < H1P_OVERFLOW_PADDING) {
198
- for (size_t i = 0; i < cookie.name_len; i++) {
199
- if (invalid_cookie_char(*cookie.name) == 0) {
200
- *(response->metadata.headers_pos++) = *(cookie.name++);
201
- continue;
202
- } else {
203
- fprintf(stderr, "Invalid cookie name cookie name character: %c\n",
204
- *cookie.name);
205
- return -1;
206
- }
207
- }
208
- } else {
209
- while (*cookie.name && overflowing(response) == 0) {
210
- if (invalid_cookie_char(*cookie.name) == 0) {
211
- *(response->metadata.headers_pos++) = *(cookie.name++);
212
- continue;
213
- } else {
214
- fprintf(stderr, "Invalid cookie name cookie name character: %c\n",
215
- *cookie.name);
216
- return -1;
217
- }
218
- }
219
- }
220
- if (overflowing(response))
221
- return -1;
222
- /* seperate name from value */
223
- *(response->metadata.headers_pos++) = '=';
224
- /* write the cookie value, if any */
225
- if (cookie.value) {
226
- if (cookie.value_len && cookie.value_len < H1P_OVERFLOW_PADDING) {
227
- for (size_t i = 0; i < cookie.value_len; i++) {
228
- if (invalid_cookie_char(*cookie.value) == 0) {
229
- *(response->metadata.headers_pos++) = *(cookie.value++);
230
- continue;
231
- } else {
232
- fprintf(stderr, "Invalid cookie value cookie name character: %c\n",
233
- *cookie.value);
234
- return -1;
235
- }
236
- }
237
- } else {
238
- while (*cookie.value && overflowing(response) == 0) {
239
- if (invalid_cookie_char(*cookie.value) == 0) {
240
- *(response->metadata.headers_pos++) = *(cookie.value++);
241
- continue;
242
- } else {
243
- fprintf(stderr, "Invalid cookie value cookie name character: %c\n",
244
- *cookie.value);
245
- return -1;
246
- }
247
- }
248
- }
249
- if (overflowing(response))
250
- return -1;
251
- } else {
252
- cookie.max_age = -1;
253
- }
254
- /* complete value data */
255
- *(response->metadata.headers_pos++) = ';';
256
- if (cookie.max_age) {
257
- response->metadata.headers_pos +=
258
- sprintf(response->metadata.headers_pos, "Max-Age=%d;", cookie.max_age);
259
- }
260
- if (cookie.domain) {
261
- memcpy(response->metadata.headers_pos, "domain=", 7);
262
- response->metadata.headers_pos += 7;
263
- if (h1p_protected_copy(response, cookie.domain, cookie.domain_len))
264
- return -1;
265
- *(response->metadata.headers_pos++) = ';';
266
- }
267
- if (cookie.path) {
268
- memcpy(response->metadata.headers_pos, "path=", 5);
269
- response->metadata.headers_pos += 5;
270
- if (h1p_protected_copy(response, cookie.path, cookie.path_len))
271
- return -1;
272
- *(response->metadata.headers_pos++) = ';';
273
- }
274
- if (cookie.http_only) {
275
- memcpy(response->metadata.headers_pos, "HttpOnly;", 9);
276
- response->metadata.headers_pos += 9;
277
- }
278
- if (cookie.secure) {
279
- memcpy(response->metadata.headers_pos, "secure;", 7);
280
- response->metadata.headers_pos += 7;
281
- }
282
- *(response->metadata.headers_pos++) = '\r';
283
- *(response->metadata.headers_pos++) = '\n';
284
- return 0;
285
- }
286
-
287
- /**
288
- Sends the headers (if unsent) and sends the body.
289
- */
290
- UNUSED_FUNC static inline int h1p_response_write_body(http_response_s *response,
291
- const char *body,
292
- size_t length) {
293
- if (!response->content_length)
294
- response->content_length = length;
295
- sock_packet_s *headers = h1p_finalize_headers(response);
296
- if (headers != NULL) { /* we haven't sent the headers yet */
297
- ssize_t i_read =
298
- ((BUFFER_PACKET_SIZE - H1P_HEADER_START) - headers->length);
299
- if (i_read > 1024) {
300
- /* we can fit at least some of the data inside the response buffer. */
301
- if ((size_t)i_read > length) {
302
- i_read = length;
303
- /* we can fit the data inside the response buffer. */
304
- memcpy(response->metadata.headers_pos, body, i_read);
305
- response->metadata.headers_pos += i_read;
306
- headers->length += i_read;
307
- return h1p_send_headers(response, headers);
308
- }
309
- memcpy(response->metadata.headers_pos, body, i_read);
310
- response->metadata.headers_pos += i_read;
311
- headers->length += i_read;
312
- length -= i_read;
313
- body += i_read;
314
- }
315
- /* we need to send the (rest of the) body seperately. */
316
- if (h1p_send_headers(response, headers))
317
- return -1;
318
- }
319
- response->metadata.headers_pos += length;
320
- return sock_write(response->metadata.fd, (void *)body, length);
321
- }
322
- /**
323
- Sends the headers (if unsent) and schedules the file to be sent.
324
- */
325
- UNUSED_FUNC static inline int h1p_response_sendfile(http_response_s *response,
326
- int source_fd, off_t offset,
327
- size_t length) {
328
- if (!response->content_length)
329
- response->content_length = length;
330
-
331
- sock_packet_s *headers = h1p_finalize_headers(response);
332
-
333
- if (headers != NULL) { /* we haven't sent the headers yet */
334
- if (headers->length < (BUFFER_PACKET_SIZE - H1P_HEADER_START)) {
335
- /* we can fit at least some of the data inside the response buffer. */
336
- ssize_t i_read = pread(
337
- source_fd, response->metadata.headers_pos,
338
- ((BUFFER_PACKET_SIZE - H1P_HEADER_START) - headers->length), offset);
339
- if (i_read > 0) {
340
- if ((size_t)i_read >= length) {
341
- headers->length += length;
342
- close(source_fd);
343
- return h1p_send_headers(response, headers);
344
- } else {
345
- headers->length += i_read;
346
- length -= i_read;
347
- offset += i_read;
348
- }
349
- }
350
- }
351
- /* we need to send the rest seperately. */
352
- if (h1p_send_headers(response, headers)) {
353
- close(source_fd);
354
- return -1;
355
- }
356
- }
357
- response->metadata.headers_pos += length;
358
- return sock_sendfile(response->metadata.fd, source_fd, offset, length);
359
- }
360
-
361
- UNUSED_FUNC static inline int h1p_response_finish(http_response_s *response) {
362
- sock_packet_s *headers = h1p_finalize_headers(response);
363
- if (headers) {
364
- return h1p_send_headers(response, headers);
365
- }
366
- if (response->metadata.should_close) {
367
- sock_close(response->metadata.fd);
368
- }
369
-
370
- return 0;
371
- }
372
-
373
- /* *****************************************************************************
374
- Cleanup
375
- ***************************************************************************** */
376
-
377
- /* clear any used definitions */
378
- #undef overflowing
379
- #undef HEADERS_FINISHED
380
- #undef invalid_cookie_char
381
- #undef h1p_validate_hpos
382
- #endif