summaryrefslogtreecommitdiffstatsabout
path: root/src/gnutls_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnutls_io.c')
-rw-r--r--src/gnutls_io.c647
1 files changed, 508 insertions, 139 deletions
diff --git a/src/gnutls_io.c b/src/gnutls_io.c
index 1cb14a3..659effa 100644
--- a/src/gnutls_io.c
+++ b/src/gnutls_io.c
@@ -19,152 +19,80 @@
19 19
20/** 20/**
21 * Describe how the GnuTLS Filter system works here 21 * Describe how the GnuTLS Filter system works here
22 * - It is basicly the same as what mod_ssl uses in that respect. 22 * - Basicly the same as what mod_ssl does with OpenSSL.
23 *
23 */ 24 */
24 25
25apr_status_t mod_gnutls_filter_input(ap_filter_t * f, 26#define HTTP_ON_HTTPS_PORT \
26 apr_bucket_brigade * bb, 27 "GET /" CRLF
27 ap_input_mode_t mode,
28 apr_read_type_e block,
29 apr_off_t readbytes)
30{
31 apr_bucket *b;
32 apr_status_t status = APR_SUCCESS;
33 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx;
34
35 if (f->c->aborted) {
36 apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
37 APR_BRIGADE_INSERT_TAIL(bb, bucket);
38 return APR_ECONNABORTED;
39 }
40
41#if 0
42 for (b = APR_BRIGADE_FIRST(bb);
43 b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
44 if (APR_BUCKET_IS_EOS(b)) {
45 /* end of connection */
46 }
47 else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
48 == APR_SUCCESS) {
49 /* more data */
50 }
51 }
52#endif
53 return status;
54}
55 28
56#define GNUTLS_HANDSHAKE_ATTEMPTS 10 29#define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \
30 apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \
31 sizeof(HTTP_ON_HTTPS_PORT) - 1, \
32 alloc)
57 33
58apr_status_t mod_gnutls_filter_output(ap_filter_t * f, 34static apr_status_t gnutls_io_filter_error(ap_filter_t * f,
59 apr_bucket_brigade * bb) 35 apr_bucket_brigade * bb,
36 apr_status_t status)
60{ 37{
61 int ret, i;
62 const char *buf = 0;
63 apr_size_t bytes = 0;
64 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx; 38 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx;
65 apr_status_t status = APR_SUCCESS; 39 apr_bucket *bucket;
66 apr_read_type_e rblock = APR_NONBLOCK_READ;
67 40
68 if (f->c->aborted) { 41 switch (status) {
69 apr_brigade_cleanup(bb); 42 case HTTP_BAD_REQUEST:
70 return APR_ECONNABORTED; 43 /* log the situation */
71 } 44 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
45 f->c->base_server,
46 "GnuTLS handshake failed: HTTP spoken on HTTPS port; "
47 "trying to send HTML error page");
72 48
73 if (ctxt->status == 0) { 49 ctxt->status = -1;
74 for (i = GNUTLS_HANDSHAKE_ATTEMPTS; i > 0; i--) {
75 ret = gnutls_handshake(ctxt->session);
76
77 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
78 continue;
79 }
80
81 if (ret < 0) {
82 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
83 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
84 ret = gnutls_alert_get(ctxt->session);
85 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,
86 "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret,
87 gnutls_alert_get_name(ret));
88 }
89 50
90 if (gnutls_error_is_fatal(ret) != 0) { 51 /* fake the request line */
91 gnutls_deinit(ctxt->session); 52 bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);
92 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server, 53 break;
93 "GnuTLS: Handshake Failed (%d) '%s'", ret,
94 gnutls_strerror(ret));
95 ctxt->status = -1;
96 break;
97 }
98 }
99 else {
100 ctxt->status = 1;
101 break; /* all done with the handshake */
102 }
103 }
104 }
105 54
106 if (ctxt->status < 0) { 55 default:
107 return ap_pass_brigade(f->next, bb); 56 return status;
108 } 57 }
109 58
110 while (!APR_BRIGADE_EMPTY(bb)) { 59 APR_BRIGADE_INSERT_TAIL(bb, bucket);
111 apr_bucket *bucket = APR_BRIGADE_FIRST(bb); 60 bucket = apr_bucket_eos_create(f->c->bucket_alloc);
112 if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) { 61 APR_BRIGADE_INSERT_TAIL(bb, bucket);
113 /** TODO: GnuTLS doesn't have a special flush method? **/
114 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
115 return status;
116 }
117 break;
118 }
119 else if (AP_BUCKET_IS_EOC(bucket)) {
120 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
121
122 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
123 return status;
124 }
125 break;
126 }
127 else {
128 /* filter output */
129 const char *data;
130 apr_size_t len;
131
132 status = apr_bucket_read(bucket, &data, &len, rblock);
133 62
134 if (APR_STATUS_IS_EAGAIN(status)) { 63 return APR_SUCCESS;
135 rblock = APR_BLOCK_READ; 64}
136 continue; /* and try again with a blocking read. */
137 }
138
139 rblock = APR_NONBLOCK_READ;
140
141 if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {
142 break;
143 }
144
145 ret = gnutls_record_send(ctxt->session, data, len);
146 if (ret < 0) {
147 /* error sending output */
148 }
149 else if ((apr_size_t) ret != len) {
150 /* not all of the data was sent. */
151 /* mod_ssl basicly errors out here.. this doesn't seem right? */
152 }
153 else {
154 /* send complete */
155
156 }
157
158 apr_bucket_delete(bucket);
159 65
160 if (status != APR_SUCCESS) { 66static int char_buffer_read(mod_gnutls_char_buffer_t * buffer, char *in,
161 break; 67 int inl)
162 } 68{
69 if (!buffer->length) {
70 return 0;
71 }
163 72
164 } 73 if (buffer->length > inl) {
74 /* we have have enough to fill the caller's buffer */
75 memcpy(in, buffer->value, inl);
76 buffer->value += inl;
77 buffer->length -= inl;
78 }
79 else {
80 /* swallow remainder of the buffer */
81 memcpy(in, buffer->value, buffer->length);
82 inl = buffer->length;
83 buffer->value = NULL;
84 buffer->length = 0;
165 } 85 }
166 86
167 return status; 87 return inl;
88}
89
90static int char_buffer_write(mod_gnutls_char_buffer_t * buffer, char *in,
91 int inl)
92{
93 buffer->value = in;
94 buffer->length = inl;
95 return inl;
168} 96}
169 97
170/** 98/**
@@ -253,16 +181,383 @@ static apr_status_t brigade_consume(apr_bucket_brigade * bb,
253} 181}
254 182
255 183
184static apr_status_t gnutls_io_input_read(mod_gnutls_handle_t * ctxt,
185 char *buf, apr_size_t * len)
186{
187 apr_size_t wanted = *len;
188 apr_size_t bytes = 0;
189 int rc;
190
191 *len = 0;
192
193 /* If we have something leftover from last time, try that first. */
194 if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) {
195 *len = bytes;
196 if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
197 /* We want to rollback this read. */
198 if (ctxt->input_cbuf.length > 0) {
199 ctxt->input_cbuf.value -= bytes;
200 ctxt->input_cbuf.length += bytes;
201 }
202 else {
203 char_buffer_write(&ctxt->input_cbuf, buf, (int) bytes);
204 }
205 return APR_SUCCESS;
206 }
207 /* This could probably be *len == wanted, but be safe from stray
208 * photons.
209 */
210 if (*len >= wanted) {
211 return APR_SUCCESS;
212 }
213 if (ctxt->input_mode == AP_MODE_GETLINE) {
214 if (memchr(buf, APR_ASCII_LF, *len)) {
215 return APR_SUCCESS;
216 }
217 }
218 else {
219 /* Down to a nonblock pattern as we have some data already
220 */
221 ctxt->input_block = APR_NONBLOCK_READ;
222 }
223 }
224
225 while (1) {
226
227 if (ctxt->status < 0) {
228 /* Ensure a non-zero error code is returned */
229 if (ctxt->input_rc == APR_SUCCESS) {
230 ctxt->input_rc = APR_EGENERAL;
231 }
232 break;
233 }
234
235 rc = gnutls_record_recv(ctxt->session, buf + bytes, wanted - bytes);
236
237 if (rc > 0) {
238 *len += rc;
239 if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
240 /* We want to rollback this read. */
241 char_buffer_write(&ctxt->input_cbuf, buf, rc);
242 }
243 return ctxt->input_rc;
244 }
245 else if (rc == 0) {
246 /* If EAGAIN, we will loop given a blocking read,
247 * otherwise consider ourselves at EOF.
248 */
249 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
250 || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
251 /* Already read something, return APR_SUCCESS instead.
252 * On win32 in particular, but perhaps on other kernels,
253 * a blocking call isn't 'always' blocking.
254 */
255 if (*len > 0) {
256 ctxt->input_rc = APR_SUCCESS;
257 break;
258 }
259 if (ctxt->input_block == APR_NONBLOCK_READ) {
260 break;
261 }
262 }
263 else {
264 if (*len > 0) {
265 ctxt->input_rc = APR_SUCCESS;
266 }
267 else {
268 ctxt->input_rc = APR_EOF;
269 }
270 break;
271 }
272 }
273 else { /* (rc < 0) */
274
275 if (rc == GNUTLS_E_REHANDSHAKE) {
276 /* A client has asked for a new Hankshake. Currently, we don't do it */
277 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
278 ctxt->c->base_server,
279 "GnuTLS: Error reading data. Client Requested a New Handshake."
280 " (%d) '%s'", rc, gnutls_strerror(rc));
281 }
282 else {
283 /* Some Other Error. Report it. Die. */
284 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
285 ctxt->c->base_server,
286 "GnuTLS: Error reading data. (%d) '%s'", rc,
287 gnutls_strerror(rc));
288 }
289
290 if (ctxt->input_rc == APR_SUCCESS) {
291 ctxt->input_rc = APR_EGENERAL;
292 }
293 break;
294 }
295 }
296 return ctxt->input_rc;
297}
298
299static apr_status_t gnutls_io_input_getline(mod_gnutls_handle_t * ctxt,
300 char *buf, apr_size_t * len)
301{
302 const char *pos = NULL;
303 apr_status_t status;
304 apr_size_t tmplen = *len, buflen = *len, offset = 0;
305
306 *len = 0;
307
308 while (tmplen > 0) {
309 status = gnutls_io_input_read(ctxt, buf + offset, &tmplen);
310
311 if (status != APR_SUCCESS) {
312 return status;
313 }
314
315 *len += tmplen;
316
317 if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
318 break;
319 }
320
321 offset += tmplen;
322 tmplen = buflen - offset;
323 }
324
325 if (pos) {
326 char *value;
327 int length;
328 apr_size_t bytes = pos - buf;
329
330 bytes += 1;
331 value = buf + bytes;
332 length = *len - bytes;
333
334 char_buffer_write(&ctxt->input_cbuf, value, length);
335
336 *len = bytes;
337 }
338
339 return APR_SUCCESS;
340}
341
342
343#define GNUTLS_HANDSHAKE_ATTEMPTS 10
344
345static void gnutls_do_handshake(mod_gnutls_handle_t * ctxt)
346{
347 int i, ret;
348
349 if (ctxt->status != 0)
350 return;
351
352 for (i = GNUTLS_HANDSHAKE_ATTEMPTS; i > 0; i--) {
353 ret = gnutls_handshake(ctxt->session);
354 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
355 continue;
356 }
357
358 if (ret < 0) {
359 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
360 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
361 ret = gnutls_alert_get(ctxt->session);
362 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server,
363 "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret,
364 gnutls_alert_get_name(ret));
365 }
366
367 if (gnutls_error_is_fatal(ret) != 0) {
368 gnutls_deinit(ctxt->session);
369 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server,
370 "GnuTLS: Handshake Failed (%d) '%s'", ret,
371 gnutls_strerror(ret));
372 ctxt->status = -1;
373 return;
374 }
375 }
376 else {
377 ctxt->status = 1;
378 return; /* all done with the handshake */
379 }
380 }
381 ctxt->status = -1;
382 return;
383}
384
385
386apr_status_t mod_gnutls_filter_input(ap_filter_t * f,
387 apr_bucket_brigade * bb,
388 ap_input_mode_t mode,
389 apr_read_type_e block,
390 apr_off_t readbytes)
391{
392 apr_status_t status = APR_SUCCESS;
393 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx;
394 apr_size_t len = sizeof(ctxt->input_buffer);
395
396 if (f->c->aborted) {
397 apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
398 APR_BRIGADE_INSERT_TAIL(bb, bucket);
399 return APR_ECONNABORTED;
400 }
401
402 if (ctxt->status == 0) {
403 gnutls_do_handshake(ctxt);
404 }
405
406 if (ctxt->status < 0) {
407 return ap_get_brigade(f->next, bb, mode, block, readbytes);
408 }
409
410 /* XXX: we don't currently support anything other than these modes. */
411 if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&
412 mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {
413 return APR_ENOTIMPL;
414 }
415
416 ctxt->input_mode = mode;
417 ctxt->input_block = block;
418
419 if (ctxt->input_mode == AP_MODE_READBYTES ||
420 ctxt->input_mode == AP_MODE_SPECULATIVE) {
421 /* Err. This is bad. readbytes *can* be a 64bit int! len.. is NOT */
422 if (readbytes < len) {
423 len = (apr_size_t) readbytes;
424 }
425 status = gnutls_io_input_read(ctxt, ctxt->input_buffer, &len);
426 }
427 else if (ctxt->input_mode == AP_MODE_GETLINE) {
428 status = gnutls_io_input_getline(ctxt, ctxt->input_buffer, &len);
429 }
430 else {
431 /* We have no idea what you are talking about, so return an error. */
432 return APR_ENOTIMPL;
433 }
434
435 if (status != APR_SUCCESS) {
436 return gnutls_io_filter_error(f, bb, status);
437 }
438
439 /* Create a transient bucket out of the decrypted data. */
440 if (len > 0) {
441 apr_bucket *bucket =
442 apr_bucket_transient_create(ctxt->input_buffer, len,
443 f->c->bucket_alloc);
444 APR_BRIGADE_INSERT_TAIL(bb, bucket);
445 }
446
447 return status;
448}
449
450apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
451 apr_bucket_brigade * bb)
452{
453 int ret;
454 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx;
455 apr_status_t status = APR_SUCCESS;
456 apr_read_type_e rblock = APR_NONBLOCK_READ;
457
458 if (f->c->aborted) {
459 apr_brigade_cleanup(bb);
460 return APR_ECONNABORTED;
461 }
462
463 if (ctxt->status == 0) {
464 gnutls_do_handshake(ctxt);
465 }
466
467 if (ctxt->status < 0) {
468 return ap_pass_brigade(f->next, bb);
469 }
470
471 while (!APR_BRIGADE_EMPTY(bb)) {
472 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
473 if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {
474 /** TODO: GnuTLS doesn't have a special flush method? **/
475 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
476 return status;
477 }
478 break;
479 }
480 else if (AP_BUCKET_IS_EOC(bucket)) {
481 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
482
483 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
484 return status;
485 }
486 break;
487 }
488 else {
489 /* filter output */
490 const char *data;
491 apr_size_t len;
492
493 status = apr_bucket_read(bucket, &data, &len, rblock);
494
495 if (APR_STATUS_IS_EAGAIN(status)) {
496 rblock = APR_BLOCK_READ;
497 continue; /* and try again with a blocking read. */
498 }
499
500 rblock = APR_NONBLOCK_READ;
501
502 if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {
503 break;
504 }
505
506 ret = gnutls_record_send(ctxt->session, data, len);
507
508 if (ret < 0) {
509 /* error sending output */
510 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->output_rc,
511 ctxt->c->base_server,
512 "GnuTLS: Error writing data."
513 " (%d) '%s'", ret, gnutls_strerror(ret));
514 if (ctxt->output_rc == APR_SUCCESS) {
515 ctxt->output_rc = APR_EGENERAL;
516 }
517 }
518 else if ((apr_size_t) ret != len) {
519 /* not all of the data was sent. */
520 /* mod_ssl basicly errors out here.. this doesn't seem right? */
521 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->output_rc,
522 ctxt->c->base_server,
523 "GnuTLS: failed to write %" APR_SSIZE_T_FMT
524 " of %" APR_SIZE_T_FMT " bytes.",
525 len - (apr_size_t) ret, len);
526 if (ctxt->output_rc == APR_SUCCESS) {
527 ctxt->output_rc = APR_EGENERAL;
528 }
529 }
530
531 apr_bucket_delete(bucket);
532
533 if (ctxt->output_rc != APR_SUCCESS) {
534 break;
535 }
536 }
537 }
538
539 return status;
540}
541
256ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr, 542ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
257 void *buffer, size_t len) 543 void *buffer, size_t len)
258{ 544{
259 mod_gnutls_handle_t *ctxt = ptr; 545 mod_gnutls_handle_t *ctxt = ptr;
260 apr_status_t rc; 546 apr_status_t rc;
261 apr_size_t in = len; 547 apr_size_t in = len;
548 apr_read_type_e block = ctxt->input_block;
549
550 ctxt->input_rc = APR_SUCCESS;
551
262 /* If Len = 0, we don't do anything. */ 552 /* If Len = 0, we don't do anything. */
263 if (!len) 553 if (!len)
264 return 0; 554 return 0;
265 555
556 if (!ctxt->input_bb) {
557 ctxt->input_rc = APR_EOF;
558 return -1;
559 }
560
266 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) { 561 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) {
267 562
268 rc = ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb, 563 rc = ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,
@@ -283,13 +578,64 @@ ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
283 } 578 }
284 } 579 }
285 580
286// brigade_consume(ctxt->input_bb, ctxt->input_block, buffer, &len); 581 ctxt->input_rc = brigade_consume(ctxt->input_bb, block, buffer, &len);
287 582
583 if (ctxt->input_rc == APR_SUCCESS) {
584 return (ssize_t) len;
585 }
288 586
289 ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb, 587 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
290 AP_MODE_READBYTES, ctxt->input_block, len); 588 || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
589 return (ssize_t) len;
590 }
291 591
292 return len; 592 /* Unexpected errors and APR_EOF clean out the brigade.
593 * Subsequent calls will return APR_EOF.
594 */
595 apr_brigade_cleanup(ctxt->input_bb);
596 ctxt->input_bb = NULL;
597
598 if (APR_STATUS_IS_EOF(ctxt->input_rc) && len) {
599 /* Provide the results of this read pass,
600 * without resetting the BIO retry_read flag
601 */
602 return (ssize_t) len;
603 }
604
605 return -1;
606}
607
608
609static ssize_t write_flush(mod_gnutls_handle_t * ctxt)
610{
611 apr_bucket *e;
612
613 if (!(ctxt->output_blen || ctxt->output_length)) {
614 ctxt->output_rc = APR_SUCCESS;
615 return 1;
616 }
617
618 if (ctxt->output_blen) {
619 e = apr_bucket_transient_create(ctxt->output_buffer,
620 ctxt->output_blen,
621 ctxt->output_bb->bucket_alloc);
622 /* we filled this buffer first so add it to the
623 * head of the brigade
624 */
625 APR_BRIGADE_INSERT_HEAD(ctxt->output_bb, e);
626 ctxt->output_blen = 0;
627 }
628
629 ctxt->output_length = 0;
630 e = apr_bucket_flush_create(ctxt->output_bb->bucket_alloc);
631 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);
632
633 ctxt->output_rc = ap_pass_brigade(ctxt->output_filter->next,
634 ctxt->output_bb);
635 /* create new brigade ready for next time through */
636 ctxt->output_bb =
637 apr_brigade_create(ctxt->c->pool, ctxt->c->bucket_alloc);
638 return (ctxt->output_rc == APR_SUCCESS) ? 1 : -1;
293} 639}
294 640
295ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr, 641ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr,
@@ -297,11 +643,34 @@ ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr,
297{ 643{
298 mod_gnutls_handle_t *ctxt = ptr; 644 mod_gnutls_handle_t *ctxt = ptr;
299 645
300// apr_bucket *bucket = apr_bucket_transient_create(in, inl, 646 if (!ctxt->output_length
301// outctx->bb-> 647 && (len + ctxt->output_blen < sizeof(ctxt->output_buffer))) {
302// bucket_alloc); 648 /* the first two SSL_writes (of 1024 and 261 bytes)
649 * need to be in the same packet (vec[0].iov_base)
650 */
651 /* XXX: could use apr_brigade_write() to make code look cleaner
652 * but this way we avoid the malloc(APR_BUCKET_BUFF_SIZE)
653 * and free() of it later
654 */
655 memcpy(&ctxt->output_buffer[ctxt->output_blen], buffer, len);
656 ctxt->output_blen += len;
657 }
658 else {
659 /* pass along the encrypted data
660 * need to flush since we're using SSL's malloc-ed buffer
661 * which will be overwritten once we leave here
662 */
663 apr_bucket *bucket = apr_bucket_transient_create(buffer, len,
664 ctxt->output_bb->
665 bucket_alloc);
666
667 ctxt->output_length += len;
668 APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, bucket);
303 669
304 // outctx->length += inl; 670 if (write_flush(ctxt) < 0) {
305 //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket); 671 return -1;
306 return 0; 672 }
673 }
674
675 return len;
307} 676}