agoo 2.5.1 → 2.5.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +12 -1
- data/ext/agoo/agoo.c +4 -3
- data/ext/agoo/bind.c +51 -11
- data/ext/agoo/bind.h +9 -0
- data/ext/agoo/con.c +127 -89
- data/ext/agoo/con.h +24 -8
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +1 -0
- data/ext/agoo/err.c +1 -1
- data/ext/agoo/err.h +2 -5
- data/ext/agoo/foo/agoo.c +109 -0
- data/ext/agoo/foo/con.c +1220 -0
- data/ext/agoo/foo/con.h +65 -0
- data/ext/agoo/foo/page.c +699 -0
- data/ext/agoo/foo/pub.c +131 -0
- data/ext/agoo/foo/pub.h +40 -0
- data/ext/agoo/foo/rserver.c +1016 -0
- data/ext/agoo/foo/server.c +303 -0
- data/ext/agoo/foo/server.h +67 -0
- data/ext/agoo/foo/upgraded.c +182 -0
- data/ext/agoo/hook.c +31 -0
- data/ext/agoo/hook.h +9 -10
- data/ext/agoo/{types.h → kinds.h} +3 -3
- data/ext/agoo/log.c +168 -83
- data/ext/agoo/log.h +6 -2
- data/ext/agoo/page.c +38 -32
- data/ext/agoo/pub.c +16 -0
- data/ext/agoo/pub.h +1 -0
- data/ext/agoo/queue.h +1 -0
- data/ext/agoo/req.c +95 -0
- data/ext/agoo/req.h +48 -0
- data/ext/agoo/request.c +10 -38
- data/ext/agoo/request.h +1 -34
- data/ext/agoo/res.h +1 -3
- data/ext/agoo/response.c +6 -248
- data/ext/agoo/response.h +2 -6
- data/ext/agoo/rlog.c +2 -1
- data/ext/agoo/rresponse.c +252 -0
- data/ext/agoo/rresponse.h +14 -0
- data/ext/agoo/rserver.c +43 -45
- data/ext/agoo/rserver.h +3 -24
- data/ext/agoo/rupgraded.c +303 -0
- data/ext/agoo/rupgraded.h +17 -0
- data/ext/agoo/server.c +125 -8
- data/ext/agoo/server.h +26 -4
- data/ext/agoo/sse.c +3 -1
- data/ext/agoo/upgraded.c +42 -280
- data/ext/agoo/upgraded.h +16 -8
- data/ext/agoo/websocket.c +13 -9
- data/lib/agoo/base.rb +84 -0
- data/lib/agoo/client.rb +25 -0
- data/lib/agoo/version.rb +1 -1
- data/test/bind_test.rb +2 -2
- metadata +22 -4
data/ext/agoo/request.h
CHANGED
@@ -7,43 +7,10 @@
|
|
7
7
|
|
8
8
|
#include <ruby.h>
|
9
9
|
|
10
|
-
#include "
|
11
|
-
#include "res.h"
|
12
|
-
#include "types.h"
|
10
|
+
#include "req.h"
|
13
11
|
|
14
|
-
struct _Server;
|
15
|
-
struct _Upgraded;
|
16
|
-
|
17
|
-
typedef enum {
|
18
|
-
UP_NONE = '\0',
|
19
|
-
UP_WS = 'W',
|
20
|
-
UP_SSE = 'S',
|
21
|
-
} Upgrade;
|
22
|
-
|
23
|
-
typedef struct _Str {
|
24
|
-
char *start;
|
25
|
-
unsigned int len;
|
26
|
-
} *Str;
|
27
|
-
|
28
|
-
typedef struct _Req {
|
29
|
-
Method method;
|
30
|
-
Upgrade upgrade;
|
31
|
-
struct _Upgraded *up;
|
32
|
-
struct _Str path;
|
33
|
-
struct _Str query;
|
34
|
-
struct _Str header;
|
35
|
-
struct _Str body;
|
36
|
-
Hook hook;
|
37
|
-
VALUE env;
|
38
|
-
Res res;
|
39
|
-
size_t mlen; // allocated msg length
|
40
|
-
char msg[8]; // expanded to be full message
|
41
|
-
} *Req;
|
42
|
-
|
43
|
-
extern Req request_create(size_t mlen);
|
44
12
|
extern void request_init(VALUE mod);
|
45
13
|
extern VALUE request_wrap(Req req);
|
46
14
|
extern VALUE request_env(Req req, VALUE self);
|
47
|
-
extern void request_destroy(Req req);
|
48
15
|
|
49
16
|
#endif // __AGOO_REQUEST_H__
|
data/ext/agoo/res.h
CHANGED
data/ext/agoo/response.c
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
2
|
|
3
|
+
#include <stdio.h>
|
3
4
|
#include <stdlib.h>
|
5
|
+
#include <string.h>
|
4
6
|
|
5
7
|
#include "debug.h"
|
6
8
|
#include "http.h"
|
7
9
|
#include "response.h"
|
8
|
-
#include "text.h"
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
static int
|
11
|
+
int
|
13
12
|
response_len(Response res) {
|
14
|
-
char
|
13
|
+
char buf[256];
|
15
14
|
const char *msg = http_code_message(res->code);
|
16
|
-
int len = snprintf(
|
15
|
+
int len = snprintf(buf, sizeof(buf), "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n", res->code, msg, res->blen);
|
17
16
|
Header h;
|
18
17
|
|
19
18
|
for (h = res->headers; NULL != h; h = h->next) {
|
@@ -25,7 +24,7 @@ response_len(Response res) {
|
|
25
24
|
return len;
|
26
25
|
}
|
27
26
|
|
28
|
-
|
27
|
+
void
|
29
28
|
response_fill(Response res, char *buf) {
|
30
29
|
Header h;
|
31
30
|
const char *msg = http_code_message(res->code);
|
@@ -44,244 +43,3 @@ response_fill(Response res, char *buf) {
|
|
44
43
|
}
|
45
44
|
*buf = '\0';
|
46
45
|
}
|
47
|
-
|
48
|
-
static void
|
49
|
-
response_free(void *ptr) {
|
50
|
-
Response res = (Response)ptr;
|
51
|
-
Header h;
|
52
|
-
|
53
|
-
while (NULL != (h = res->headers)) {
|
54
|
-
res->headers = h->next;
|
55
|
-
DEBUG_FREE(mem_header, h);
|
56
|
-
xfree(h);
|
57
|
-
}
|
58
|
-
DEBUG_FREE(mem_res_body, res->body);
|
59
|
-
DEBUG_FREE(mem_response, ptr);
|
60
|
-
free(res->body); // allocated with strdup
|
61
|
-
xfree(ptr);
|
62
|
-
}
|
63
|
-
|
64
|
-
VALUE
|
65
|
-
response_new( ) {
|
66
|
-
Response res = ALLOC(struct _Response);
|
67
|
-
|
68
|
-
DEBUG_ALLOC(mem_response, res)
|
69
|
-
memset(res, 0, sizeof(struct _Response));
|
70
|
-
res->code = 200;
|
71
|
-
|
72
|
-
return Data_Wrap_Struct(res_class, NULL, response_free, res);
|
73
|
-
}
|
74
|
-
|
75
|
-
/* Document-method: to_s
|
76
|
-
*
|
77
|
-
* call-seq: to_s()
|
78
|
-
*
|
79
|
-
* Returns a string representation of the response.
|
80
|
-
*/
|
81
|
-
static VALUE
|
82
|
-
to_s(VALUE self) {
|
83
|
-
Response res = (Response)DATA_PTR(self);
|
84
|
-
int len = response_len(res);
|
85
|
-
char *s = ALLOC_N(char, len + 1);
|
86
|
-
|
87
|
-
DEBUG_ALLOC(mem_to_s, s)
|
88
|
-
response_fill(res, s);
|
89
|
-
|
90
|
-
return rb_str_new(s, len);
|
91
|
-
}
|
92
|
-
|
93
|
-
/* Document-method: content
|
94
|
-
*
|
95
|
-
* call-seq: content()
|
96
|
-
*
|
97
|
-
* alias for _body_
|
98
|
-
*/
|
99
|
-
|
100
|
-
/* Document-method: body
|
101
|
-
*
|
102
|
-
* call-seq: body()
|
103
|
-
*
|
104
|
-
* Gets the HTTP body for the response.
|
105
|
-
*/
|
106
|
-
static VALUE
|
107
|
-
body_get(VALUE self) {
|
108
|
-
Response res = (Response)DATA_PTR(self);
|
109
|
-
|
110
|
-
if (NULL == res->body) {
|
111
|
-
return Qnil;
|
112
|
-
}
|
113
|
-
return rb_str_new(res->body, res->blen);
|
114
|
-
}
|
115
|
-
|
116
|
-
/* Document-method: content=
|
117
|
-
*
|
118
|
-
* call-seq: content=(str)
|
119
|
-
*
|
120
|
-
* alias for _body=_
|
121
|
-
*/
|
122
|
-
|
123
|
-
/* Document-method: body=
|
124
|
-
*
|
125
|
-
* call-seq: body=(str)
|
126
|
-
*
|
127
|
-
* Sets the HTTP body for the response.
|
128
|
-
*/
|
129
|
-
static VALUE
|
130
|
-
body_set(VALUE self, VALUE val) {
|
131
|
-
Response res = (Response)DATA_PTR(self);
|
132
|
-
|
133
|
-
if (T_STRING == rb_type(val)) {
|
134
|
-
res->body = strdup(StringValuePtr(val));
|
135
|
-
DEBUG_ALLOC(mem_res_body, res->body)
|
136
|
-
res->blen = (int)RSTRING_LEN(val);
|
137
|
-
} else {
|
138
|
-
rb_raise(rb_eArgError, "Expected a string");
|
139
|
-
// TBD use Oj to encode val
|
140
|
-
}
|
141
|
-
return Qnil;
|
142
|
-
}
|
143
|
-
|
144
|
-
/* Document-method: code
|
145
|
-
*
|
146
|
-
* call-seq: code()
|
147
|
-
*
|
148
|
-
* Gets the HTTP status code for the response.
|
149
|
-
*/
|
150
|
-
static VALUE
|
151
|
-
code_get(VALUE self) {
|
152
|
-
return INT2NUM(((Response)DATA_PTR(self))->code);
|
153
|
-
}
|
154
|
-
|
155
|
-
/* Document-method: code=
|
156
|
-
*
|
157
|
-
* call-seq: code=(value)
|
158
|
-
*
|
159
|
-
* Sets the HTTP status code for the response.
|
160
|
-
*/
|
161
|
-
static VALUE
|
162
|
-
code_set(VALUE self, VALUE val) {
|
163
|
-
int code = NUM2INT(val);
|
164
|
-
|
165
|
-
if (100 <= code && code < 600) {
|
166
|
-
((Response)DATA_PTR(self))->code = code;
|
167
|
-
} else {
|
168
|
-
rb_raise(rb_eArgError, "%d is not a valid HTTP status code.", code);
|
169
|
-
}
|
170
|
-
return Qnil;
|
171
|
-
}
|
172
|
-
|
173
|
-
/* Document-method: []
|
174
|
-
*
|
175
|
-
* call-seq: [](key)
|
176
|
-
*
|
177
|
-
* Gets a header element associated with the _key_.
|
178
|
-
*/
|
179
|
-
static VALUE
|
180
|
-
head_get(VALUE self, VALUE key) {
|
181
|
-
Response res = (Response)DATA_PTR(self);
|
182
|
-
Header h;
|
183
|
-
const char *ks = StringValuePtr(key);
|
184
|
-
int klen = (int)RSTRING_LEN(key);
|
185
|
-
|
186
|
-
for (h = res->headers; NULL != h; h = h->next) {
|
187
|
-
if (0 == strncasecmp(h->text, ks, klen) && klen + 1 < h->len && ':' == h->text[klen]) {
|
188
|
-
return rb_str_new(h->text + klen + 2, h->len - klen - 4);
|
189
|
-
}
|
190
|
-
}
|
191
|
-
return Qnil;
|
192
|
-
}
|
193
|
-
|
194
|
-
/* Document-method: []=
|
195
|
-
*
|
196
|
-
* call-seq: []=(key, value)
|
197
|
-
*
|
198
|
-
* Sets a header element with the _key_ and _value_ provided.
|
199
|
-
*/
|
200
|
-
static VALUE
|
201
|
-
head_set(VALUE self, VALUE key, VALUE val) {
|
202
|
-
Response res = (Response)DATA_PTR(self);
|
203
|
-
Header h;
|
204
|
-
Header prev = NULL;
|
205
|
-
const char *ks = StringValuePtr(key);
|
206
|
-
const char *vs;
|
207
|
-
int klen = (int)RSTRING_LEN(key);
|
208
|
-
int vlen;
|
209
|
-
int hlen;
|
210
|
-
|
211
|
-
for (h = res->headers; NULL != h; h = h->next) {
|
212
|
-
if (0 == strncasecmp(h->text, ks, klen) && klen + 1 < h->len && ':' == h->text[klen]) {
|
213
|
-
if (NULL == prev) {
|
214
|
-
res->headers = h->next;
|
215
|
-
} else {
|
216
|
-
prev->next = h->next;
|
217
|
-
}
|
218
|
-
DEBUG_FREE(mem_header, h);
|
219
|
-
xfree(h);
|
220
|
-
break;
|
221
|
-
}
|
222
|
-
prev = h;
|
223
|
-
}
|
224
|
-
if (T_STRING != rb_type(val)) {
|
225
|
-
val = rb_funcall(val, rb_intern("to_s"), 0);
|
226
|
-
}
|
227
|
-
vs = StringValuePtr(val);
|
228
|
-
vlen = (int)RSTRING_LEN(val);
|
229
|
-
|
230
|
-
if (the_server.pedantic) {
|
231
|
-
struct _Err err = ERR_INIT;
|
232
|
-
|
233
|
-
if (ERR_OK != http_header_ok(&err, ks, klen, vs, vlen)) {
|
234
|
-
rb_raise(rb_eArgError, "%s", err.msg);
|
235
|
-
}
|
236
|
-
}
|
237
|
-
hlen = klen + vlen + 4;
|
238
|
-
h = (Header)ALLOC_N(char, sizeof(struct _Header) - 8 + hlen + 1);
|
239
|
-
DEBUG_ALLOC(mem_header, h)
|
240
|
-
|
241
|
-
h->next = NULL;
|
242
|
-
h->len = hlen;
|
243
|
-
strncpy(h->text, ks, klen);
|
244
|
-
strcpy(h->text + klen, ": ");
|
245
|
-
strncpy(h->text + klen + 2, vs, vlen);
|
246
|
-
strcpy(h->text + klen + 2 + vlen, "\r\n");
|
247
|
-
if (NULL == res->headers) {
|
248
|
-
res->headers = h;
|
249
|
-
} else {
|
250
|
-
for (prev = res->headers; NULL != prev->next; prev = prev->next) {
|
251
|
-
}
|
252
|
-
prev->next = h;
|
253
|
-
}
|
254
|
-
return Qnil;
|
255
|
-
}
|
256
|
-
|
257
|
-
Text
|
258
|
-
response_text(VALUE self) {
|
259
|
-
Response res = (Response)DATA_PTR(self);
|
260
|
-
int len = response_len(res);
|
261
|
-
Text t = text_allocate(len);
|
262
|
-
|
263
|
-
response_fill(res, t->text);
|
264
|
-
t->len = len;
|
265
|
-
|
266
|
-
return t;
|
267
|
-
}
|
268
|
-
|
269
|
-
/* Document-class: Agoo::Response
|
270
|
-
*
|
271
|
-
* A response passed to a handler that responds to the _on_request_
|
272
|
-
* method. The expected response is modified by the handler before returning.
|
273
|
-
*/
|
274
|
-
void
|
275
|
-
response_init(VALUE mod) {
|
276
|
-
res_class = rb_define_class_under(mod, "Response", rb_cObject);
|
277
|
-
|
278
|
-
rb_define_method(res_class, "to_s", to_s, 0);
|
279
|
-
rb_define_method(res_class, "body", body_get, 0);
|
280
|
-
rb_define_method(res_class, "body=", body_set, 1);
|
281
|
-
rb_define_method(res_class, "content", body_get, 0);
|
282
|
-
rb_define_method(res_class, "content=", body_set, 1);
|
283
|
-
rb_define_method(res_class, "code", code_get, 0);
|
284
|
-
rb_define_method(res_class, "code=", code_set, 1);
|
285
|
-
rb_define_method(res_class, "[]", head_get, 1);
|
286
|
-
rb_define_method(res_class, "[]=", head_set, 2);
|
287
|
-
}
|
data/ext/agoo/response.h
CHANGED
@@ -6,8 +6,6 @@
|
|
6
6
|
#include <stdatomic.h>
|
7
7
|
#include <stdbool.h>
|
8
8
|
|
9
|
-
#include <ruby.h>
|
10
|
-
|
11
9
|
#include "server.h"
|
12
10
|
#include "text.h"
|
13
11
|
|
@@ -24,9 +22,7 @@ typedef struct _Response {
|
|
24
22
|
char *body;
|
25
23
|
} *Response;
|
26
24
|
|
27
|
-
extern
|
28
|
-
|
29
|
-
extern VALUE response_new();
|
30
|
-
extern Text response_text(VALUE self);
|
25
|
+
extern int response_len(Response res);
|
26
|
+
extern void response_fill(Response res, char *buf);
|
31
27
|
|
32
28
|
#endif // __AGOO_RESPONSE_H__
|
data/ext/agoo/rlog.c
CHANGED
@@ -0,0 +1,252 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <stdlib.h>
|
4
|
+
|
5
|
+
#include "debug.h"
|
6
|
+
#include "http.h"
|
7
|
+
#include "response.h"
|
8
|
+
#include "rresponse.h"
|
9
|
+
#include "text.h"
|
10
|
+
|
11
|
+
static VALUE res_class = Qundef;
|
12
|
+
|
13
|
+
static void
|
14
|
+
response_free(void *ptr) {
|
15
|
+
Response res = (Response)ptr;
|
16
|
+
Header h;
|
17
|
+
|
18
|
+
while (NULL != (h = res->headers)) {
|
19
|
+
res->headers = h->next;
|
20
|
+
DEBUG_FREE(mem_header, h);
|
21
|
+
xfree(h);
|
22
|
+
}
|
23
|
+
DEBUG_FREE(mem_res_body, res->body);
|
24
|
+
DEBUG_FREE(mem_response, ptr);
|
25
|
+
free(res->body); // allocated with strdup
|
26
|
+
xfree(ptr);
|
27
|
+
}
|
28
|
+
|
29
|
+
VALUE
|
30
|
+
response_new( ) {
|
31
|
+
Response res = ALLOC(struct _Response);
|
32
|
+
|
33
|
+
DEBUG_ALLOC(mem_response, res)
|
34
|
+
memset(res, 0, sizeof(struct _Response));
|
35
|
+
res->code = 200;
|
36
|
+
|
37
|
+
return Data_Wrap_Struct(res_class, NULL, response_free, res);
|
38
|
+
}
|
39
|
+
|
40
|
+
/* Document-method: to_s
|
41
|
+
*
|
42
|
+
* call-seq: to_s()
|
43
|
+
*
|
44
|
+
* Returns a string representation of the response.
|
45
|
+
*/
|
46
|
+
static VALUE
|
47
|
+
to_s(VALUE self) {
|
48
|
+
Response res = (Response)DATA_PTR(self);
|
49
|
+
int len = response_len(res);
|
50
|
+
char *s = ALLOC_N(char, len + 1);
|
51
|
+
|
52
|
+
DEBUG_ALLOC(mem_to_s, s)
|
53
|
+
response_fill(res, s);
|
54
|
+
|
55
|
+
return rb_str_new(s, len);
|
56
|
+
}
|
57
|
+
|
58
|
+
/* Document-method: content
|
59
|
+
*
|
60
|
+
* call-seq: content()
|
61
|
+
*
|
62
|
+
* alias for _body_
|
63
|
+
*/
|
64
|
+
|
65
|
+
/* Document-method: body
|
66
|
+
*
|
67
|
+
* call-seq: body()
|
68
|
+
*
|
69
|
+
* Gets the HTTP body for the response.
|
70
|
+
*/
|
71
|
+
static VALUE
|
72
|
+
body_get(VALUE self) {
|
73
|
+
Response res = (Response)DATA_PTR(self);
|
74
|
+
|
75
|
+
if (NULL == res->body) {
|
76
|
+
return Qnil;
|
77
|
+
}
|
78
|
+
return rb_str_new(res->body, res->blen);
|
79
|
+
}
|
80
|
+
|
81
|
+
/* Document-method: content=
|
82
|
+
*
|
83
|
+
* call-seq: content=(str)
|
84
|
+
*
|
85
|
+
* alias for _body=_
|
86
|
+
*/
|
87
|
+
|
88
|
+
/* Document-method: body=
|
89
|
+
*
|
90
|
+
* call-seq: body=(str)
|
91
|
+
*
|
92
|
+
* Sets the HTTP body for the response.
|
93
|
+
*/
|
94
|
+
static VALUE
|
95
|
+
body_set(VALUE self, VALUE val) {
|
96
|
+
Response res = (Response)DATA_PTR(self);
|
97
|
+
|
98
|
+
if (T_STRING == rb_type(val)) {
|
99
|
+
res->body = strdup(StringValuePtr(val));
|
100
|
+
DEBUG_ALLOC(mem_res_body, res->body)
|
101
|
+
res->blen = (int)RSTRING_LEN(val);
|
102
|
+
} else {
|
103
|
+
rb_raise(rb_eArgError, "Expected a string");
|
104
|
+
// TBD use Oj to encode val
|
105
|
+
}
|
106
|
+
return Qnil;
|
107
|
+
}
|
108
|
+
|
109
|
+
/* Document-method: code
|
110
|
+
*
|
111
|
+
* call-seq: code()
|
112
|
+
*
|
113
|
+
* Gets the HTTP status code for the response.
|
114
|
+
*/
|
115
|
+
static VALUE
|
116
|
+
code_get(VALUE self) {
|
117
|
+
return INT2NUM(((Response)DATA_PTR(self))->code);
|
118
|
+
}
|
119
|
+
|
120
|
+
/* Document-method: code=
|
121
|
+
*
|
122
|
+
* call-seq: code=(value)
|
123
|
+
*
|
124
|
+
* Sets the HTTP status code for the response.
|
125
|
+
*/
|
126
|
+
static VALUE
|
127
|
+
code_set(VALUE self, VALUE val) {
|
128
|
+
int code = NUM2INT(val);
|
129
|
+
|
130
|
+
if (100 <= code && code < 600) {
|
131
|
+
((Response)DATA_PTR(self))->code = code;
|
132
|
+
} else {
|
133
|
+
rb_raise(rb_eArgError, "%d is not a valid HTTP status code.", code);
|
134
|
+
}
|
135
|
+
return Qnil;
|
136
|
+
}
|
137
|
+
|
138
|
+
/* Document-method: []
|
139
|
+
*
|
140
|
+
* call-seq: [](key)
|
141
|
+
*
|
142
|
+
* Gets a header element associated with the _key_.
|
143
|
+
*/
|
144
|
+
static VALUE
|
145
|
+
head_get(VALUE self, VALUE key) {
|
146
|
+
Response res = (Response)DATA_PTR(self);
|
147
|
+
Header h;
|
148
|
+
const char *ks = StringValuePtr(key);
|
149
|
+
int klen = (int)RSTRING_LEN(key);
|
150
|
+
|
151
|
+
for (h = res->headers; NULL != h; h = h->next) {
|
152
|
+
if (0 == strncasecmp(h->text, ks, klen) && klen + 1 < h->len && ':' == h->text[klen]) {
|
153
|
+
return rb_str_new(h->text + klen + 2, h->len - klen - 4);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
return Qnil;
|
157
|
+
}
|
158
|
+
|
159
|
+
/* Document-method: []=
|
160
|
+
*
|
161
|
+
* call-seq: []=(key, value)
|
162
|
+
*
|
163
|
+
* Sets a header element with the _key_ and _value_ provided.
|
164
|
+
*/
|
165
|
+
static VALUE
|
166
|
+
head_set(VALUE self, VALUE key, VALUE val) {
|
167
|
+
Response res = (Response)DATA_PTR(self);
|
168
|
+
Header h;
|
169
|
+
Header prev = NULL;
|
170
|
+
const char *ks = StringValuePtr(key);
|
171
|
+
const char *vs;
|
172
|
+
int klen = (int)RSTRING_LEN(key);
|
173
|
+
int vlen;
|
174
|
+
int hlen;
|
175
|
+
|
176
|
+
for (h = res->headers; NULL != h; h = h->next) {
|
177
|
+
if (0 == strncasecmp(h->text, ks, klen) && klen + 1 < h->len && ':' == h->text[klen]) {
|
178
|
+
if (NULL == prev) {
|
179
|
+
res->headers = h->next;
|
180
|
+
} else {
|
181
|
+
prev->next = h->next;
|
182
|
+
}
|
183
|
+
DEBUG_FREE(mem_header, h);
|
184
|
+
xfree(h);
|
185
|
+
break;
|
186
|
+
}
|
187
|
+
prev = h;
|
188
|
+
}
|
189
|
+
if (T_STRING != rb_type(val)) {
|
190
|
+
val = rb_funcall(val, rb_intern("to_s"), 0);
|
191
|
+
}
|
192
|
+
vs = StringValuePtr(val);
|
193
|
+
vlen = (int)RSTRING_LEN(val);
|
194
|
+
|
195
|
+
if (the_server.pedantic) {
|
196
|
+
struct _Err err = ERR_INIT;
|
197
|
+
|
198
|
+
if (ERR_OK != http_header_ok(&err, ks, klen, vs, vlen)) {
|
199
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
hlen = klen + vlen + 4;
|
203
|
+
h = (Header)ALLOC_N(char, sizeof(struct _Header) - 8 + hlen + 1);
|
204
|
+
DEBUG_ALLOC(mem_header, h)
|
205
|
+
|
206
|
+
h->next = NULL;
|
207
|
+
h->len = hlen;
|
208
|
+
strncpy(h->text, ks, klen);
|
209
|
+
strcpy(h->text + klen, ": ");
|
210
|
+
strncpy(h->text + klen + 2, vs, vlen);
|
211
|
+
strcpy(h->text + klen + 2 + vlen, "\r\n");
|
212
|
+
if (NULL == res->headers) {
|
213
|
+
res->headers = h;
|
214
|
+
} else {
|
215
|
+
for (prev = res->headers; NULL != prev->next; prev = prev->next) {
|
216
|
+
}
|
217
|
+
prev->next = h;
|
218
|
+
}
|
219
|
+
return Qnil;
|
220
|
+
}
|
221
|
+
|
222
|
+
Text
|
223
|
+
response_text(VALUE self) {
|
224
|
+
Response res = (Response)DATA_PTR(self);
|
225
|
+
int len = response_len(res);
|
226
|
+
Text t = text_allocate(len);
|
227
|
+
|
228
|
+
response_fill(res, t->text);
|
229
|
+
t->len = len;
|
230
|
+
|
231
|
+
return t;
|
232
|
+
}
|
233
|
+
|
234
|
+
/* Document-class: Agoo::Response
|
235
|
+
*
|
236
|
+
* A response passed to a handler that responds to the _on_request_
|
237
|
+
* method. The expected response is modified by the handler before returning.
|
238
|
+
*/
|
239
|
+
void
|
240
|
+
response_init(VALUE mod) {
|
241
|
+
res_class = rb_define_class_under(mod, "Response", rb_cObject);
|
242
|
+
|
243
|
+
rb_define_method(res_class, "to_s", to_s, 0);
|
244
|
+
rb_define_method(res_class, "body", body_get, 0);
|
245
|
+
rb_define_method(res_class, "body=", body_set, 1);
|
246
|
+
rb_define_method(res_class, "content", body_get, 0);
|
247
|
+
rb_define_method(res_class, "content=", body_set, 1);
|
248
|
+
rb_define_method(res_class, "code", code_get, 0);
|
249
|
+
rb_define_method(res_class, "code=", code_set, 1);
|
250
|
+
rb_define_method(res_class, "[]", head_get, 1);
|
251
|
+
rb_define_method(res_class, "[]=", head_set, 2);
|
252
|
+
}
|