Changeset dae0aec in mod_gnutls for src/gnutls_io.c


Ignore:
Timestamp:
Sep 27, 2004, 8:20:51 PM (19 years ago)
Author:
Paul Querna <chip@…>
Branches:
asyncio, debian/master, debian/stretch-backports, jessie-backports, main, master, msva, proxy-ticket, upstream
Children:
b1f7f11
Parents:
2e12226
Message:

input and output filters

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_io.c

    r2e12226 rdae0aec  
    2020/**
    2121 * 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 *
    2324 */
    2425
    25 apr_status_t mod_gnutls_filter_input(ap_filter_t * f,
    26                                      apr_bucket_brigade * bb,
    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;
     26#define HTTP_ON_HTTPS_PORT \
     27    "GET /" CRLF
     28
     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)
     33
     34static apr_status_t gnutls_io_filter_error(ap_filter_t * f,
     35                                           apr_bucket_brigade * bb,
     36                                           apr_status_t status)
     37{
    3338    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 
    56 #define GNUTLS_HANDSHAKE_ATTEMPTS 10
    57 
    58 apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
    59                                       apr_bucket_brigade * bb)
    60 {
    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;
    65     apr_status_t status = APR_SUCCESS;
    66     apr_read_type_e rblock = APR_NONBLOCK_READ;
    67 
    68     if (f->c->aborted) {
    69         apr_brigade_cleanup(bb);
    70         return APR_ECONNABORTED;
    71     }
    72 
    73     if (ctxt->status == 0) {
    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 
    90                 if (gnutls_error_is_fatal(ret) != 0) {
    91                     gnutls_deinit(ctxt->session);
    92                     ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,
    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 
    106     if (ctxt->status < 0) {
    107         return ap_pass_brigade(f->next, bb);
    108     }
    109 
    110     while (!APR_BRIGADE_EMPTY(bb)) {
    111         apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
    112         if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(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 
    134             if (APR_STATUS_IS_EAGAIN(status)) {
    135                 rblock = APR_BLOCK_READ;
    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 
    160             if (status != APR_SUCCESS) {
    161                 break;
    162             }
    163 
    164         }
    165     }
    166 
    167     return status;
     39    apr_bucket *bucket;
     40
     41    switch (status) {
     42    case HTTP_BAD_REQUEST:
     43        /* log the situation */
     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");
     48
     49        ctxt->status = -1;
     50
     51        /* fake the request line */
     52        bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);
     53        break;
     54
     55    default:
     56        return status;
     57    }
     58
     59    APR_BRIGADE_INSERT_TAIL(bb, bucket);
     60    bucket = apr_bucket_eos_create(f->c->bucket_alloc);
     61    APR_BRIGADE_INSERT_TAIL(bb, bucket);
     62
     63    return APR_SUCCESS;
     64}
     65
     66static int char_buffer_read(mod_gnutls_char_buffer_t * buffer, char *in,
     67                            int inl)
     68{
     69    if (!buffer->length) {
     70        return 0;
     71    }
     72
     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;
     85    }
     86
     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;
    16896}
    16997
     
    254182
    255183
     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
    256542ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
    257543                                  void *buffer, size_t len)
     
    260546    apr_status_t rc;
    261547    apr_size_t in = len;
     548    apr_read_type_e block = ctxt->input_block;
     549
     550    ctxt->input_rc = APR_SUCCESS;
     551
    262552    /* If Len = 0, we don't do anything. */
    263553    if (!len)
    264554        return 0;
     555
     556    if (!ctxt->input_bb) {
     557        ctxt->input_rc = APR_EOF;
     558        return -1;
     559    }
    265560
    266561    if (APR_BRIGADE_EMPTY(ctxt->input_bb)) {
     
    284579    }
    285580
    286 //    brigade_consume(ctxt->input_bb, ctxt->input_block, buffer, &len);
    287 
    288 
    289     ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,
    290                    AP_MODE_READBYTES, ctxt->input_block, len);
    291 
    292     return len;
     581    ctxt->input_rc = brigade_consume(ctxt->input_bb, block, buffer, &len);
     582
     583    if (ctxt->input_rc == APR_SUCCESS) {
     584        return (ssize_t) len;
     585    }
     586
     587    if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
     588        || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
     589        return (ssize_t) len;
     590    }
     591
     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;
    293639}
    294640
     
    298644    mod_gnutls_handle_t *ctxt = ptr;
    299645
    300 //    apr_bucket *bucket = apr_bucket_transient_create(in, inl,
    301 //                                                     outctx->bb->
    302 //                                                     bucket_alloc);
    303 
    304     //  outctx->length += inl;
    305     //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);
    306     return 0;
    307 }
     646    if (!ctxt->output_length
     647        && (len + ctxt->output_blen < sizeof(ctxt->output_buffer))) {
     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);
     669
     670        if (write_flush(ctxt) < 0) {
     671            return -1;
     672        }
     673    }
     674
     675    return len;
     676}
Note: See TracChangeset for help on using the changeset viewer.