couchbase 1.1.5-x86-mingw32 → 1.2.0.beta-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -1
- data/.travis.yml +12 -1
- data/HISTORY.markdown +112 -1
- data/README.markdown +149 -6
- data/couchbase.gemspec +5 -1
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +973 -0
- data/ext/couchbase_ext/arithmetic.c +322 -0
- data/ext/couchbase_ext/bucket.c +1092 -0
- data/ext/couchbase_ext/couchbase_ext.c +618 -3247
- data/ext/couchbase_ext/couchbase_ext.h +519 -0
- data/ext/couchbase_ext/delete.c +167 -0
- data/ext/couchbase_ext/extconf.rb +24 -5
- data/ext/couchbase_ext/get.c +301 -0
- data/ext/couchbase_ext/gethrtime.c +124 -0
- data/ext/couchbase_ext/http.c +402 -0
- data/ext/couchbase_ext/observe.c +174 -0
- data/ext/couchbase_ext/result.c +126 -0
- data/ext/couchbase_ext/stats.c +169 -0
- data/ext/couchbase_ext/store.c +522 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +190 -0
- data/ext/couchbase_ext/unlock.c +180 -0
- data/ext/couchbase_ext/utils.c +471 -0
- data/ext/couchbase_ext/version.c +147 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +356 -0
- data/lib/couchbase.rb +24 -3
- data/lib/couchbase/bucket.rb +372 -9
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/utils.rb +59 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +305 -0
- data/lib/couchbase/view_row.rb +230 -0
- data/lib/ext/multi_json_fix.rb +47 -0
- data/lib/rack/session/couchbase.rb +104 -0
- data/tasks/compile.rake +5 -14
- data/test/setup.rb +6 -2
- data/test/test_arithmetic.rb +32 -2
- data/test/test_async.rb +18 -4
- data/test/test_bucket.rb +11 -1
- data/test/test_cas.rb +13 -3
- data/test/test_couchbase_rails_cache_store.rb +294 -0
- data/test/test_delete.rb +60 -3
- data/test/test_format.rb +28 -17
- data/test/test_get.rb +91 -14
- data/test/test_store.rb +31 -1
- data/test/{test_flush.rb → test_timer.rb} +11 -18
- data/test/test_touch.rb +33 -5
- data/test/test_unlock.rb +120 -0
- data/test/test_utils.rb +26 -0
- metadata +102 -12
@@ -0,0 +1,471 @@
|
|
1
|
+
/* vim: ft=c et ts=8 sts=4 sw=4 cino=
|
2
|
+
*
|
3
|
+
* Copyright 2011, 2012 Couchbase, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include "couchbase_ext.h"
|
19
|
+
|
20
|
+
VALUE
|
21
|
+
cb_gc_protect(struct bucket_st *bucket, VALUE val)
|
22
|
+
{
|
23
|
+
rb_hash_aset(bucket->object_space, val|1, val);
|
24
|
+
return val;
|
25
|
+
}
|
26
|
+
|
27
|
+
VALUE
|
28
|
+
cb_gc_unprotect(struct bucket_st *bucket, VALUE val)
|
29
|
+
{
|
30
|
+
rb_funcall(bucket->object_space, id_delete, 1, val|1);
|
31
|
+
return val;
|
32
|
+
}
|
33
|
+
|
34
|
+
VALUE
|
35
|
+
cb_proc_call(VALUE recv, int argc, ...)
|
36
|
+
{
|
37
|
+
VALUE *argv;
|
38
|
+
va_list ar;
|
39
|
+
int arity;
|
40
|
+
int ii;
|
41
|
+
|
42
|
+
arity = FIX2INT(rb_funcall(recv, id_arity, 0));
|
43
|
+
if (arity < 0) {
|
44
|
+
arity = argc;
|
45
|
+
}
|
46
|
+
if (arity > 0) {
|
47
|
+
va_init_list(ar, argc);
|
48
|
+
argv = ALLOCA_N(VALUE, argc);
|
49
|
+
for (ii = 0; ii < arity; ++ii) {
|
50
|
+
if (ii < argc) {
|
51
|
+
argv[ii] = va_arg(ar, VALUE);
|
52
|
+
} else {
|
53
|
+
argv[ii] = Qnil;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
va_end(ar);
|
57
|
+
} else {
|
58
|
+
argv = NULL;
|
59
|
+
}
|
60
|
+
return rb_funcall2(recv, id_call, arity, argv);
|
61
|
+
}
|
62
|
+
|
63
|
+
VALUE
|
64
|
+
cb_hash_delete(VALUE hash, VALUE key)
|
65
|
+
{
|
66
|
+
return rb_funcall(hash, id_delete, 1, key);
|
67
|
+
}
|
68
|
+
|
69
|
+
/* Helper to convert return code from libcouchbase to meaningful exception.
|
70
|
+
* Returns nil if the code considering successful and exception object
|
71
|
+
* otherwise. Store given string to exceptions as message, and also
|
72
|
+
* initialize +error+ attribute with given return code. */
|
73
|
+
VALUE
|
74
|
+
cb_check_error_with_status(lcb_error_t rc, const char *msg, VALUE key,
|
75
|
+
lcb_http_status_t status)
|
76
|
+
{
|
77
|
+
VALUE klass, exc, str;
|
78
|
+
char buf[300];
|
79
|
+
|
80
|
+
if (rc == LCB_SUCCESS || rc == LCB_AUTH_CONTINUE) {
|
81
|
+
return Qnil;
|
82
|
+
}
|
83
|
+
switch (rc) {
|
84
|
+
case LCB_AUTH_ERROR:
|
85
|
+
klass = eAuthError;
|
86
|
+
break;
|
87
|
+
case LCB_DELTA_BADVAL:
|
88
|
+
klass = eDeltaBadvalError;
|
89
|
+
break;
|
90
|
+
case LCB_E2BIG:
|
91
|
+
klass = eTooBigError;
|
92
|
+
break;
|
93
|
+
case LCB_EBUSY:
|
94
|
+
klass = eBusyError;
|
95
|
+
break;
|
96
|
+
case LCB_EINTERNAL:
|
97
|
+
klass = eInternalError;
|
98
|
+
break;
|
99
|
+
case LCB_EINVAL:
|
100
|
+
klass = eInvalidError;
|
101
|
+
break;
|
102
|
+
case LCB_ENOMEM:
|
103
|
+
klass = eNoMemoryError;
|
104
|
+
break;
|
105
|
+
case LCB_ERANGE:
|
106
|
+
klass = eRangeError;
|
107
|
+
break;
|
108
|
+
case LCB_ETMPFAIL:
|
109
|
+
klass = eTmpFailError;
|
110
|
+
break;
|
111
|
+
case LCB_KEY_EEXISTS:
|
112
|
+
klass = eKeyExistsError;
|
113
|
+
break;
|
114
|
+
case LCB_KEY_ENOENT:
|
115
|
+
klass = eNotFoundError;
|
116
|
+
break;
|
117
|
+
case LCB_LIBEVENT_ERROR:
|
118
|
+
klass = eLibeventError;
|
119
|
+
break;
|
120
|
+
case LCB_NETWORK_ERROR:
|
121
|
+
klass = eNetworkError;
|
122
|
+
break;
|
123
|
+
case LCB_NOT_MY_VBUCKET:
|
124
|
+
klass = eNotMyVbucketError;
|
125
|
+
break;
|
126
|
+
case LCB_NOT_STORED:
|
127
|
+
klass = eNotStoredError;
|
128
|
+
break;
|
129
|
+
case LCB_NOT_SUPPORTED:
|
130
|
+
klass = eNotSupportedError;
|
131
|
+
break;
|
132
|
+
case LCB_UNKNOWN_COMMAND:
|
133
|
+
klass = eUnknownCommandError;
|
134
|
+
break;
|
135
|
+
case LCB_UNKNOWN_HOST:
|
136
|
+
klass = eUnknownHostError;
|
137
|
+
break;
|
138
|
+
case LCB_PROTOCOL_ERROR:
|
139
|
+
klass = eProtocolError;
|
140
|
+
break;
|
141
|
+
case LCB_ETIMEDOUT:
|
142
|
+
klass = eTimeoutError;
|
143
|
+
break;
|
144
|
+
case LCB_CONNECT_ERROR:
|
145
|
+
klass = eConnectError;
|
146
|
+
break;
|
147
|
+
case LCB_BUCKET_ENOENT:
|
148
|
+
klass = eBucketNotFoundError;
|
149
|
+
break;
|
150
|
+
case LCB_CLIENT_ENOMEM:
|
151
|
+
klass = eClientNoMemoryError;
|
152
|
+
break;
|
153
|
+
case LCB_ERROR:
|
154
|
+
/* fall through */
|
155
|
+
default:
|
156
|
+
klass = eLibcouchbaseError;
|
157
|
+
}
|
158
|
+
|
159
|
+
str = rb_str_buf_new2(msg ? msg : "");
|
160
|
+
rb_str_buf_cat2(str, " (");
|
161
|
+
if (key != Qnil) {
|
162
|
+
snprintf(buf, 300, "key=\"%s\", ", RSTRING_PTR(key));
|
163
|
+
rb_str_buf_cat2(str, buf);
|
164
|
+
}
|
165
|
+
if (status > 0) {
|
166
|
+
const char *reason = NULL;
|
167
|
+
snprintf(buf, 300, "status=\"%d\"", status);
|
168
|
+
rb_str_buf_cat2(str, buf);
|
169
|
+
switch (status) {
|
170
|
+
case LCB_HTTP_STATUS_BAD_REQUEST:
|
171
|
+
reason = " (Bad Request)";
|
172
|
+
break;
|
173
|
+
case LCB_HTTP_STATUS_UNAUTHORIZED:
|
174
|
+
reason = " (Unauthorized)";
|
175
|
+
break;
|
176
|
+
case LCB_HTTP_STATUS_PAYMENT_REQUIRED:
|
177
|
+
reason = " (Payment Required)";
|
178
|
+
break;
|
179
|
+
case LCB_HTTP_STATUS_FORBIDDEN:
|
180
|
+
reason = " (Forbidden)";
|
181
|
+
break;
|
182
|
+
case LCB_HTTP_STATUS_NOT_FOUND:
|
183
|
+
reason = " (Not Found)";
|
184
|
+
break;
|
185
|
+
case LCB_HTTP_STATUS_METHOD_NOT_ALLOWED:
|
186
|
+
reason = " (Method Not Allowed)";
|
187
|
+
break;
|
188
|
+
case LCB_HTTP_STATUS_NOT_ACCEPTABLE:
|
189
|
+
reason = " (Not Acceptable)";
|
190
|
+
break;
|
191
|
+
case LCB_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
|
192
|
+
reason = " (Proxy Authentication Required)";
|
193
|
+
break;
|
194
|
+
case LCB_HTTP_STATUS_REQUEST_TIMEOUT:
|
195
|
+
reason = " (Request Timeout)";
|
196
|
+
break;
|
197
|
+
case LCB_HTTP_STATUS_CONFLICT:
|
198
|
+
reason = " (Conflict)";
|
199
|
+
break;
|
200
|
+
case LCB_HTTP_STATUS_GONE:
|
201
|
+
reason = " (Gone)";
|
202
|
+
break;
|
203
|
+
case LCB_HTTP_STATUS_LENGTH_REQUIRED:
|
204
|
+
reason = " (Length Required)";
|
205
|
+
break;
|
206
|
+
case LCB_HTTP_STATUS_PRECONDITION_FAILED:
|
207
|
+
reason = " (Precondition Failed)";
|
208
|
+
break;
|
209
|
+
case LCB_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE:
|
210
|
+
reason = " (Request Entity Too Large)";
|
211
|
+
break;
|
212
|
+
case LCB_HTTP_STATUS_REQUEST_URI_TOO_LONG:
|
213
|
+
reason = " (Request Uri Too Long)";
|
214
|
+
break;
|
215
|
+
case LCB_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
|
216
|
+
reason = " (Unsupported Media Type)";
|
217
|
+
break;
|
218
|
+
case LCB_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE:
|
219
|
+
reason = " (Requested Range Not Satisfiable)";
|
220
|
+
break;
|
221
|
+
case LCB_HTTP_STATUS_EXPECTATION_FAILED:
|
222
|
+
reason = " (Expectation Failed)";
|
223
|
+
break;
|
224
|
+
case LCB_HTTP_STATUS_UNPROCESSABLE_ENTITY:
|
225
|
+
reason = " (Unprocessable Entity)";
|
226
|
+
break;
|
227
|
+
case LCB_HTTP_STATUS_LOCKED:
|
228
|
+
reason = " (Locked)";
|
229
|
+
break;
|
230
|
+
case LCB_HTTP_STATUS_FAILED_DEPENDENCY:
|
231
|
+
reason = " (Failed Dependency)";
|
232
|
+
break;
|
233
|
+
case LCB_HTTP_STATUS_INTERNAL_SERVER_ERROR:
|
234
|
+
reason = " (Internal Server Error)";
|
235
|
+
break;
|
236
|
+
case LCB_HTTP_STATUS_NOT_IMPLEMENTED:
|
237
|
+
reason = " (Not Implemented)";
|
238
|
+
break;
|
239
|
+
case LCB_HTTP_STATUS_BAD_GATEWAY:
|
240
|
+
reason = " (Bad Gateway)";
|
241
|
+
break;
|
242
|
+
case LCB_HTTP_STATUS_SERVICE_UNAVAILABLE:
|
243
|
+
reason = " (Service Unavailable)";
|
244
|
+
break;
|
245
|
+
case LCB_HTTP_STATUS_GATEWAY_TIMEOUT:
|
246
|
+
reason = " (Gateway Timeout)";
|
247
|
+
break;
|
248
|
+
case LCB_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
|
249
|
+
reason = " (Http Version Not Supported)";
|
250
|
+
break;
|
251
|
+
case LCB_HTTP_STATUS_INSUFFICIENT_STORAGE:
|
252
|
+
reason = " (Insufficient Storage)";
|
253
|
+
break;
|
254
|
+
default:
|
255
|
+
reason = "";
|
256
|
+
}
|
257
|
+
rb_str_buf_cat2(str, reason);
|
258
|
+
rb_str_buf_cat2(str, ", ");
|
259
|
+
|
260
|
+
}
|
261
|
+
snprintf(buf, 300, "error=0x%02x)", rc);
|
262
|
+
rb_str_buf_cat2(str, buf);
|
263
|
+
exc = rb_exc_new3(klass, str);
|
264
|
+
rb_ivar_set(exc, id_iv_error, INT2FIX(rc));
|
265
|
+
rb_ivar_set(exc, id_iv_key, key);
|
266
|
+
rb_ivar_set(exc, id_iv_cas, Qnil);
|
267
|
+
rb_ivar_set(exc, id_iv_operation, Qnil);
|
268
|
+
rb_ivar_set(exc, id_iv_status, status ? INT2FIX(status) : Qnil);
|
269
|
+
return exc;
|
270
|
+
}
|
271
|
+
|
272
|
+
VALUE
|
273
|
+
cb_check_error(lcb_error_t rc, const char *msg, VALUE key)
|
274
|
+
{
|
275
|
+
return cb_check_error_with_status(rc, msg, key, 0);
|
276
|
+
}
|
277
|
+
|
278
|
+
|
279
|
+
uint32_t
|
280
|
+
flags_set_format(uint32_t flags, ID format)
|
281
|
+
{
|
282
|
+
flags &= ~((uint32_t)FMT_MASK); /* clear format bits */
|
283
|
+
|
284
|
+
if (format == sym_document) {
|
285
|
+
return flags | FMT_DOCUMENT;
|
286
|
+
} else if (format == sym_marshal) {
|
287
|
+
return flags | FMT_MARSHAL;
|
288
|
+
} else if (format == sym_plain) {
|
289
|
+
return flags | FMT_PLAIN;
|
290
|
+
}
|
291
|
+
return flags; /* document is the default */
|
292
|
+
}
|
293
|
+
|
294
|
+
ID
|
295
|
+
flags_get_format(uint32_t flags)
|
296
|
+
{
|
297
|
+
flags &= FMT_MASK; /* select format bits */
|
298
|
+
|
299
|
+
switch (flags) {
|
300
|
+
case FMT_DOCUMENT:
|
301
|
+
return sym_document;
|
302
|
+
case FMT_MARSHAL:
|
303
|
+
return sym_marshal;
|
304
|
+
case FMT_PLAIN:
|
305
|
+
/* fall through */
|
306
|
+
default:
|
307
|
+
/* all other formats treated as plain */
|
308
|
+
return sym_plain;
|
309
|
+
}
|
310
|
+
}
|
311
|
+
|
312
|
+
|
313
|
+
static VALUE
|
314
|
+
do_encode(VALUE *args)
|
315
|
+
{
|
316
|
+
VALUE val = args[0];
|
317
|
+
uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
|
318
|
+
|
319
|
+
switch (flags) {
|
320
|
+
case FMT_DOCUMENT:
|
321
|
+
return rb_funcall(mMultiJson, id_dump, 1, val);
|
322
|
+
case FMT_MARSHAL:
|
323
|
+
return rb_funcall(mMarshal, id_dump, 1, val);
|
324
|
+
case FMT_PLAIN:
|
325
|
+
/* fall through */
|
326
|
+
default:
|
327
|
+
/* all other formats treated as plain */
|
328
|
+
return val;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
static VALUE
|
333
|
+
do_decode(VALUE *args)
|
334
|
+
{
|
335
|
+
VALUE blob = args[0];
|
336
|
+
VALUE force_format = args[2];
|
337
|
+
|
338
|
+
if (TYPE(force_format) == T_SYMBOL) {
|
339
|
+
if (force_format == sym_document) {
|
340
|
+
return rb_funcall(mMultiJson, id_load, 1, blob);
|
341
|
+
} else if (force_format == sym_marshal) {
|
342
|
+
return rb_funcall(mMarshal, id_load, 1, blob);
|
343
|
+
} else { /* sym_plain and any other symbol */
|
344
|
+
return blob;
|
345
|
+
}
|
346
|
+
} else {
|
347
|
+
uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
|
348
|
+
|
349
|
+
switch (flags) {
|
350
|
+
case FMT_DOCUMENT:
|
351
|
+
return rb_funcall(mMultiJson, id_load, 1, blob);
|
352
|
+
case FMT_MARSHAL:
|
353
|
+
return rb_funcall(mMarshal, id_load, 1, blob);
|
354
|
+
case FMT_PLAIN:
|
355
|
+
/* fall through */
|
356
|
+
default:
|
357
|
+
/* all other formats treated as plain */
|
358
|
+
return blob;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
static VALUE
|
364
|
+
coding_failed(void)
|
365
|
+
{
|
366
|
+
return Qundef;
|
367
|
+
}
|
368
|
+
|
369
|
+
VALUE
|
370
|
+
encode_value(VALUE val, uint32_t flags)
|
371
|
+
{
|
372
|
+
VALUE blob, args[2];
|
373
|
+
|
374
|
+
args[0] = val;
|
375
|
+
args[1] = (VALUE)flags;
|
376
|
+
/* FIXME re-raise proper exception */
|
377
|
+
blob = rb_rescue(do_encode, (VALUE)args, coding_failed, 0);
|
378
|
+
/* it must be bytestring after all */
|
379
|
+
if (TYPE(blob) != T_STRING) {
|
380
|
+
return Qundef;
|
381
|
+
}
|
382
|
+
return blob;
|
383
|
+
}
|
384
|
+
|
385
|
+
VALUE
|
386
|
+
decode_value(VALUE blob, uint32_t flags, VALUE force_format)
|
387
|
+
{
|
388
|
+
VALUE val, args[3];
|
389
|
+
|
390
|
+
/* first it must be bytestring */
|
391
|
+
if (TYPE(blob) != T_STRING) {
|
392
|
+
return Qundef;
|
393
|
+
}
|
394
|
+
args[0] = blob;
|
395
|
+
args[1] = (VALUE)flags;
|
396
|
+
args[2] = (VALUE)force_format;
|
397
|
+
val = rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
|
398
|
+
return val;
|
399
|
+
}
|
400
|
+
|
401
|
+
void
|
402
|
+
strip_key_prefix(struct bucket_st *bucket, VALUE key)
|
403
|
+
{
|
404
|
+
if (bucket->key_prefix) {
|
405
|
+
rb_str_update(key, 0, RSTRING_LEN(bucket->key_prefix_val), STR_NEW_CSTR(""));
|
406
|
+
}
|
407
|
+
}
|
408
|
+
|
409
|
+
VALUE
|
410
|
+
unify_key(struct bucket_st *bucket, VALUE key, int apply_prefix)
|
411
|
+
{
|
412
|
+
VALUE ret = Qnil, tmp;
|
413
|
+
|
414
|
+
if (bucket->key_prefix && apply_prefix) {
|
415
|
+
ret = rb_str_dup(bucket->key_prefix_val);
|
416
|
+
}
|
417
|
+
switch (TYPE(key)) {
|
418
|
+
case T_STRING:
|
419
|
+
return NIL_P(ret) ? key : rb_str_concat(ret, key);
|
420
|
+
case T_SYMBOL:
|
421
|
+
tmp = STR_NEW_CSTR(rb_id2name(SYM2ID(key)));
|
422
|
+
return NIL_P(ret) ? tmp : rb_str_concat(ret, tmp);
|
423
|
+
default: /* call #to_str or raise error */
|
424
|
+
tmp = StringValue(key);
|
425
|
+
return NIL_P(ret) ? tmp : rb_str_concat(ret, tmp);
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
void
|
430
|
+
cb_build_headers(struct context_st *ctx, const char * const *headers)
|
431
|
+
{
|
432
|
+
if (!ctx->headers_built) {
|
433
|
+
VALUE key = Qnil, val;
|
434
|
+
for (size_t ii = 1; *headers != NULL; ++ii, ++headers) {
|
435
|
+
if (ii % 2 == 0) {
|
436
|
+
if (key == Qnil) {
|
437
|
+
break;
|
438
|
+
}
|
439
|
+
val = rb_hash_aref(ctx->headers_val, key);
|
440
|
+
switch (TYPE(val)) {
|
441
|
+
case T_NIL:
|
442
|
+
rb_hash_aset(ctx->headers_val, key, STR_NEW_CSTR(*headers));
|
443
|
+
break;
|
444
|
+
case T_ARRAY:
|
445
|
+
rb_ary_push(val, STR_NEW_CSTR(*headers));
|
446
|
+
break;
|
447
|
+
default:
|
448
|
+
{
|
449
|
+
VALUE ary = rb_ary_new();
|
450
|
+
rb_ary_push(ary, val);
|
451
|
+
rb_ary_push(ary, STR_NEW_CSTR(*headers));
|
452
|
+
rb_hash_aset(ctx->headers_val, key, ary);
|
453
|
+
}
|
454
|
+
}
|
455
|
+
} else {
|
456
|
+
key = STR_NEW_CSTR(*headers);
|
457
|
+
}
|
458
|
+
}
|
459
|
+
ctx->headers_built = 1;
|
460
|
+
}
|
461
|
+
}
|
462
|
+
|
463
|
+
int
|
464
|
+
cb_first_value_i(VALUE key, VALUE value, VALUE arg)
|
465
|
+
{
|
466
|
+
VALUE *val = (VALUE *)arg;
|
467
|
+
|
468
|
+
*val = value;
|
469
|
+
(void)key;
|
470
|
+
return ST_STOP;
|
471
|
+
}
|