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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +36 -3
- data/bin/config.ru +23 -2
- data/bin/http-hello +1 -1
- data/bin/ws-shootout +5 -0
- data/ext/iodine/defer.c +468 -0
- data/ext/iodine/defer.h +105 -0
- data/ext/iodine/evio.c +263 -0
- data/ext/iodine/evio.h +133 -0
- data/ext/iodine/extconf.rb +2 -1
- data/ext/iodine/facil.c +958 -0
- data/ext/iodine/facil.h +423 -0
- data/ext/iodine/http.c +90 -0
- data/ext/iodine/http.h +50 -12
- data/ext/iodine/http1.c +200 -267
- data/ext/iodine/http1.h +17 -26
- data/ext/iodine/http1_request.c +81 -0
- data/ext/iodine/http1_request.h +58 -0
- data/ext/iodine/http1_response.c +403 -0
- data/ext/iodine/http1_response.h +90 -0
- data/ext/iodine/http1_simple_parser.c +124 -108
- data/ext/iodine/http1_simple_parser.h +8 -3
- data/ext/iodine/http_request.c +104 -0
- data/ext/iodine/http_request.h +58 -102
- data/ext/iodine/http_response.c +212 -208
- data/ext/iodine/http_response.h +89 -252
- data/ext/iodine/iodine_core.c +57 -46
- data/ext/iodine/iodine_core.h +3 -1
- data/ext/iodine/iodine_http.c +105 -81
- data/ext/iodine/iodine_websocket.c +17 -13
- data/ext/iodine/iodine_websocket.h +1 -0
- data/ext/iodine/rb-call.c +9 -7
- data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
- data/ext/iodine/rb-rack-io.c +12 -6
- data/ext/iodine/rb-rack-io.h +1 -1
- data/ext/iodine/rb-registry.c +5 -2
- data/ext/iodine/sock.c +1159 -0
- data/ext/iodine/{libsock.h → sock.h} +138 -142
- data/ext/iodine/spnlock.inc +77 -0
- data/ext/iodine/websockets.c +101 -112
- data/ext/iodine/websockets.h +38 -19
- data/iodine.gemspec +3 -3
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +6 -6
- metadata +23 -19
- data/ext/iodine/http_response_http1.h +0 -382
- data/ext/iodine/libasync.c +0 -570
- data/ext/iodine/libasync.h +0 -122
- data/ext/iodine/libreact.c +0 -350
- data/ext/iodine/libreact.h +0 -244
- data/ext/iodine/libserver.c +0 -957
- data/ext/iodine/libserver.h +0 -481
- data/ext/iodine/libsock.c +0 -1025
- data/ext/iodine/spnlock.h +0 -243
data/iodine.gemspec
CHANGED
@@ -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" \
|
data/lib/iodine/version.rb
CHANGED
data/lib/rack/handler/iodine.rb
CHANGED
@@ -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.
|
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-
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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-
|
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/
|
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
|